Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
		
			
				
	
	
		
			3464 lines
		
	
	
	
		
			79 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3464 lines
		
	
	
	
		
			79 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * sound/gus_wave.c
 | 
						|
 *
 | 
						|
 * Driver for the Gravis UltraSound wave table synth.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * Copyright (C) by Hannu Savolainen 1993-1997
 | 
						|
 *
 | 
						|
 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 | 
						|
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
 | 
						|
 * for more info.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * Thomas Sailer    : ioctl code reworked (vmalloc/vfree removed)
 | 
						|
 * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
 | 
						|
 *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
 | 
						|
 * Bartlomiej Zolnierkiewicz : added some __init/__exit
 | 
						|
 */
 | 
						|
 
 | 
						|
#include <linux/init.h> 
 | 
						|
#include <linux/config.h>
 | 
						|
#include <linux/spinlock.h>
 | 
						|
 | 
						|
#define GUSPNP_AUTODETECT
 | 
						|
 | 
						|
#include "sound_config.h"
 | 
						|
#include <linux/ultrasound.h>
 | 
						|
 | 
						|
#include "gus.h"
 | 
						|
#include "gus_hw.h"
 | 
						|
 | 
						|
#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
 | 
						|
 | 
						|
#define MAX_SAMPLE	150
 | 
						|
#define MAX_PATCH	256
 | 
						|
 | 
						|
#define NOT_SAMPLE	0xffff
 | 
						|
 | 
						|
struct voice_info
 | 
						|
{
 | 
						|
	unsigned long   orig_freq;
 | 
						|
	unsigned long   current_freq;
 | 
						|
	unsigned long   mode;
 | 
						|
	int             fixed_pitch;
 | 
						|
	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
 | 
						|
#define VMODE_START_NOTE	3
 | 
						|
 | 
						|
	int             env_phase;
 | 
						|
	unsigned char   env_rate[6];
 | 
						|
	unsigned char   env_offset[6];
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Volume computation parameters for gus_adagio_vol()
 | 
						|
	 */
 | 
						|
	int		main_vol, expression_vol, patch_vol;
 | 
						|
 | 
						|
	/* Variables for "Ultraclick" removal */
 | 
						|
	int             dev_pending, note_pending, volume_pending,
 | 
						|
	                sample_pending;
 | 
						|
	char            kill_pending;
 | 
						|
	long            offset_pending;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
static struct voice_alloc_info *voice_alloc;
 | 
						|
static struct address_info *gus_hw_config;
 | 
						|
extern int      gus_base;
 | 
						|
extern int      gus_irq, gus_dma;
 | 
						|
extern int      gus_pnp_flag;
 | 
						|
extern int      gus_no_wave_dma;
 | 
						|
static int      gus_dma2 = -1;
 | 
						|
static int      dual_dma_mode;
 | 
						|
static long     gus_mem_size;
 | 
						|
static long     free_mem_ptr;
 | 
						|
static int      gus_busy;
 | 
						|
static int      gus_no_dma;
 | 
						|
static int      nr_voices;
 | 
						|
static int      gus_devnum;
 | 
						|
static int      volume_base, volume_scale, volume_method;
 | 
						|
static int      gus_recmask = SOUND_MASK_MIC;
 | 
						|
static int      recording_active;
 | 
						|
static int      only_read_access;
 | 
						|
static int      only_8_bits;
 | 
						|
 | 
						|
static int      iw_mode = 0;
 | 
						|
int             gus_wave_volume = 60;
 | 
						|
int             gus_pcm_volume = 80;
 | 
						|
int             have_gus_max = 0;
 | 
						|
static int      gus_line_vol = 100, gus_mic_vol;
 | 
						|
static unsigned char mix_image = 0x00;
 | 
						|
 | 
						|
int             gus_timer_enabled = 0;
 | 
						|
 | 
						|
/*
 | 
						|
 * Current version of this driver doesn't allow synth and PCM functions
 | 
						|
 * at the same time. The active_device specifies the active driver
 | 
						|
 */
 | 
						|
 | 
						|
static int      active_device;
 | 
						|
 | 
						|
#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 */
 | 
						|
 | 
						|
static int      gus_audio_speed;
 | 
						|
static int      gus_audio_channels;
 | 
						|
static int      gus_audio_bits;
 | 
						|
static int      gus_audio_bsize;
 | 
						|
static char     bounce_buf[8 * 1024];	/* Must match value set to max_fragment */
 | 
						|
 | 
						|
static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper);
 | 
						|
 | 
						|
/*
 | 
						|
 * Variables and buffers for PCM output
 | 
						|
 */
 | 
						|
 | 
						|
#define MAX_PCM_BUFFERS		(128*MAX_REALTIME_FACTOR)	/* Don't change */
 | 
						|
 | 
						|
static int      pcm_bsize, pcm_nblk, pcm_banksize;
 | 
						|
static int      pcm_datasize[MAX_PCM_BUFFERS];
 | 
						|
static volatile int pcm_head, pcm_tail, pcm_qlen;
 | 
						|
static volatile int pcm_active;
 | 
						|
static volatile int dma_active;
 | 
						|
static int      pcm_opened;
 | 
						|
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;
 | 
						|
DEFINE_SPINLOCK(gus_lock);
 | 
						|
 | 
						|
extern int     *gus_osp;
 | 
						|
 | 
						|
static struct voice_info voices[32];
 | 
						|
 | 
						|
static int      freq_div_table[] =
 | 
						|
{
 | 
						|
	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 */
 | 
						|
};
 | 
						|
 | 
						|
static struct patch_info *samples;
 | 
						|
static long     sample_ptrs[MAX_SAMPLE + 1];
 | 
						|
static int      sample_map[32];
 | 
						|
static int      free_sample;
 | 
						|
static int      mixer_type;
 | 
						|
 | 
						|
 | 
						|
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);
 | 
						|
extern unsigned short gus_linear_vol(int vol, int mainvol);
 | 
						|
static void     compute_volume(int voice, int volume);
 | 
						|
static void     do_volume_irq(int voice);
 | 
						|
static void     set_input_volumes(void);
 | 
						|
static void     gus_tmr_install(int io_base);
 | 
						|
 | 
						|
#define	INSTANT_RAMP		-1	/* Instant change. No ramping */
 | 
						|
#define FAST_RAMP		0	/* Fastest possible ramp */
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
	gus_poke(0, 0);		/* Put a silent sample to the beginning */
 | 
						|
	gus_poke(1, 0);
 | 
						|
	free_mem_ptr = 2;
 | 
						|
 | 
						|
	free_sample = 0;
 | 
						|
 | 
						|
	for (i = 0; i < MAX_PATCH; i++)
 | 
						|
		patch_table[i] = NOT_SAMPLE;
 | 
						|
}
 | 
						|
 | 
						|
void gus_delay(void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < 7; i++)
 | 
						|
		inb(u_DRAMIO);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_poke(long addr, unsigned char data)
 | 
						|
{				/* Writes a byte to the DRAM */
 | 
						|
	outb((0x43), u_Command);
 | 
						|
	outb((addr & 0xff), u_DataLo);
 | 
						|
	outb(((addr >> 8) & 0xff), u_DataHi);
 | 
						|
 | 
						|
	outb((0x44), u_Command);
 | 
						|
	outb(((addr >> 16) & 0xff), u_DataHi);
 | 
						|
	outb((data), u_DRAMIO);
 | 
						|
}
 | 
						|
 | 
						|
static unsigned char gus_peek(long addr)
 | 
						|
{				/* Reads a byte from the DRAM */
 | 
						|
	unsigned char   tmp;
 | 
						|
 | 
						|
	outb((0x43), u_Command);
 | 
						|
	outb((addr & 0xff), u_DataLo);
 | 
						|
	outb(((addr >> 8) & 0xff), u_DataHi);
 | 
						|
 | 
						|
	outb((0x44), u_Command);
 | 
						|
	outb(((addr >> 16) & 0xff), u_DataHi);
 | 
						|
	tmp = inb(u_DRAMIO);
 | 
						|
 | 
						|
	return tmp;
 | 
						|
}
 | 
						|
 | 
						|
void gus_write8(int reg, unsigned int data)
 | 
						|
{				/* Writes to an indirect register (8 bit) */
 | 
						|
	outb((reg), u_Command);
 | 
						|
	outb(((unsigned char) (data & 0xff)), u_DataHi);
 | 
						|
}
 | 
						|
 | 
						|
static unsigned char gus_read8(int reg)
 | 
						|
{				
 | 
						|
	/* Reads from an indirect register (8 bit). Offset 0x80. */
 | 
						|
	unsigned char   val;
 | 
						|
 | 
						|
	outb((reg | 0x80), u_Command);
 | 
						|
	val = inb(u_DataHi);
 | 
						|
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static unsigned char gus_look8(int reg)
 | 
						|
{
 | 
						|
	/* Reads from an indirect register (8 bit). No additional offset. */
 | 
						|
	unsigned char   val;
 | 
						|
 | 
						|
	outb((reg), u_Command);
 | 
						|
	val = inb(u_DataHi);
 | 
						|
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static void gus_write16(int reg, unsigned int data)
 | 
						|
{
 | 
						|
	/* Writes to an indirect register (16 bit) */
 | 
						|
	outb((reg), u_Command);
 | 
						|
 | 
						|
	outb(((unsigned char) (data & 0xff)), u_DataLo);
 | 
						|
	outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi);
 | 
						|
}
 | 
						|
 | 
						|
static unsigned short gus_read16(int reg)
 | 
						|
{
 | 
						|
	/* Reads from an indirect register (16 bit). Offset 0x80. */
 | 
						|
	unsigned char   hi, lo;
 | 
						|
 | 
						|
	outb((reg | 0x80), u_Command);
 | 
						|
 | 
						|
	lo = inb(u_DataLo);
 | 
						|
	hi = inb(u_DataHi);
 | 
						|
 | 
						|
	return ((hi << 8) & 0xff00) | lo;
 | 
						|
}
 | 
						|
 | 
						|
static unsigned short gus_look16(int reg)
 | 
						|
{		
 | 
						|
	/* Reads from an indirect register (16 bit). No additional offset. */
 | 
						|
	unsigned char   hi, lo;
 | 
						|
 | 
						|
	outb((reg), u_Command);
 | 
						|
 | 
						|
	lo = inb(u_DataLo);
 | 
						|
	hi = inb(u_DataHi);
 | 
						|
 | 
						|
	return ((hi << 8) & 0xff00) | lo;
 | 
						|
}
 | 
						|
 | 
						|
static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit)
 | 
						|
{
 | 
						|
	/* Writes an 24 bit memory address */
 | 
						|
	unsigned long   hold_address;
 | 
						|
 | 
						|
	if (is16bit)
 | 
						|
	{
 | 
						|
		if (iw_mode)
 | 
						|
		{
 | 
						|
			/* Interwave spesific address translations */
 | 
						|
			address >>= 1;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/*
 | 
						|
			 * 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)
 | 
						|
		    + (frac << 5));
 | 
						|
	/* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */
 | 
						|
	gus_delay();
 | 
						|
	gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
 | 
						|
	gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
 | 
						|
		    + (frac << 5));
 | 
						|
}
 | 
						|
 | 
						|
static void gus_select_voice(int voice)
 | 
						|
{
 | 
						|
	if (voice < 0 || voice > 31)
 | 
						|
		return;
 | 
						|
	outb((voice), u_Voice);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_select_max_voices(int nvoices)
 | 
						|
{
 | 
						|
	if (iw_mode)
 | 
						|
		nvoices = 32;
 | 
						|
	if (nvoices < 14)
 | 
						|
		nvoices = 14;
 | 
						|
	if (nvoices > 32)
 | 
						|
		nvoices = 32;
 | 
						|
 | 
						|
	voice_alloc->max_voice = nr_voices = nvoices;
 | 
						|
	gus_write8(0x0e, (nvoices - 1) | 0xc0);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_on(unsigned int mode)
 | 
						|
{
 | 
						|
	gus_write8(0x00, (unsigned char) (mode & 0xfc));
 | 
						|
	gus_delay();
 | 
						|
	gus_write8(0x00, (unsigned char) (mode & 0xfc));
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_off(void)
 | 
						|
{
 | 
						|
	gus_write8(0x00, gus_read8(0x00) | 0x03);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_mode(unsigned int m)
 | 
						|
{
 | 
						|
	unsigned char   mode = (unsigned char) (m & 0xff);
 | 
						|
 | 
						|
	gus_write8(0x00, (gus_read8(0x00) & 0x03) |
 | 
						|
		   (mode & 0xfc));	/* Don't touch last two bits */
 | 
						|
	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;
 | 
						|
 | 
						|
	/* Interwave plays at 44100 Hz with any number of voices */
 | 
						|
	if (iw_mode)
 | 
						|
		fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100);
 | 
						|
	else
 | 
						|
		fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
 | 
						|
	fc = fc << 1;
 | 
						|
 | 
						|
	gus_write16(0x01, fc);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_volume(unsigned int vol)
 | 
						|
{
 | 
						|
	gus_write8(0x0d, 0x03);	/* Stop ramp before setting volume */
 | 
						|
	gus_write16(0x09, (unsigned short) (vol << 4));
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_balance(unsigned int balance)
 | 
						|
{
 | 
						|
	gus_write8(0x0c, (unsigned char) (balance & 0xff));
 | 
						|
}
 | 
						|
 | 
						|
static void gus_ramp_range(unsigned int low, unsigned int high)
 | 
						|
{
 | 
						|
	gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff));
 | 
						|
	gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff));
 | 
						|
}
 | 
						|
 | 
						|
static void gus_ramp_rate(unsigned int scale, unsigned int rate)
 | 
						|
{
 | 
						|
	gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
 | 
						|
}
 | 
						|
 | 
						|
static void gus_rampon(unsigned int m)
 | 
						|
{
 | 
						|
	unsigned char   mode = (unsigned char) (m & 0xff);
 | 
						|
 | 
						|
	gus_write8(0x0d, mode & 0xfc);
 | 
						|
	gus_delay();
 | 
						|
	gus_write8(0x0d, mode & 0xfc);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_ramp_mode(unsigned int m)
 | 
						|
{
 | 
						|
	unsigned char mode = (unsigned char) (m & 0xff);
 | 
						|
 | 
						|
	gus_write8(0x0d, (gus_read8(0x0d) & 0x03) |
 | 
						|
		   (mode & 0xfc));	/* Leave the last 2 bits alone */
 | 
						|
	gus_delay();
 | 
						|
	gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc));
 | 
						|
}
 | 
						|
 | 
						|
static void gus_rampoff(void)
 | 
						|
{
 | 
						|
	gus_write8(0x0d, 0x03);
 | 
						|
}
 | 
						|
 | 
						|
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, 0,
 | 
						|
				 samples[sample_no].mode & WAVE_16_BITS);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_init(int voice)
 | 
						|
{
 | 
						|
	unsigned long   flags;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
	gus_voice_volume(0);
 | 
						|
	gus_voice_off();
 | 
						|
	gus_write_addr(0x0a, 0, 0, 0);	/* Set current position to 0 */
 | 
						|
	gus_write8(0x00, 0x03);	/* Voice off */
 | 
						|
	gus_write8(0x0d, 0x03);	/* Ramping off */
 | 
						|
	voice_alloc->map[voice] = 0;
 | 
						|
	voice_alloc->alloc_times[voice] = 0;
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_init2(int voice)
 | 
						|
{
 | 
						|
	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;
 | 
						|
	voices[voice].sample_pending = -1;
 | 
						|
	voices[voice].fixed_pitch = 0;
 | 
						|
}
 | 
						|
 | 
						|
static void step_envelope(int voice)
 | 
						|
{
 | 
						|
	unsigned        vol, prev_vol, phase;
 | 
						|
	unsigned char   rate;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
 | 
						|
	{
 | 
						|
		spin_lock_irqsave(&gus_lock,flags);
 | 
						|
		gus_select_voice(voice);
 | 
						|
		gus_rampoff();
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		return;
 | 
						|
		/*
 | 
						|
		 * Sustain phase begins. Continue envelope after receiving note off.
 | 
						|
		 */
 | 
						|
	}
 | 
						|
	if (voices[voice].env_phase >= 5)
 | 
						|
	{
 | 
						|
		/* Envelope finished. Shoot the voice down */
 | 
						|
		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];
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
 | 
						|
	gus_voice_volume(prev_vol);
 | 
						|
 | 
						|
 | 
						|
	gus_write8(0x06, rate);	/* Ramping rate */
 | 
						|
 | 
						|
	voices[voice].volume_irq_mode = VMODE_ENVELOPE;
 | 
						|
 | 
						|
	if (((vol - prev_vol) / 64) == 0)	/* No significant volume change */
 | 
						|
	{
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		step_envelope(voice);		/* Continue the envelope on the next step */
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	if (vol > prev_vol)
 | 
						|
	{
 | 
						|
		if (vol >= (4096 - 64))
 | 
						|
			vol = 4096 - 65;
 | 
						|
		gus_ramp_range(0, vol);
 | 
						|
		gus_rampon(0x20);	/* Increasing volume, with IRQ */
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (vol <= 64)
 | 
						|
			vol = 65;
 | 
						|
		gus_ramp_range(vol, 4030);
 | 
						|
		gus_rampon(0x60);	/* Decreasing volume, with IRQ */
 | 
						|
	}
 | 
						|
	voices[voice].current_volume = vol;
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
static void init_envelope(int voice)
 | 
						|
{
 | 
						|
	voices[voice].env_phase = -1;
 | 
						|
	voices[voice].current_volume = 64;
 | 
						|
 | 
						|
	step_envelope(voice);
 | 
						|
}
 | 
						|
 | 
						|
static void start_release(int voice)
 | 
						|
{
 | 
						|
	if (gus_read8(0x00) & 0x03)
 | 
						|
		return;		/* Voice already stopped */
 | 
						|
 | 
						|
	voices[voice].env_phase = 2;	/* Will be incremented by step_envelope */
 | 
						|
 | 
						|
	voices[voice].current_volume = voices[voice].initial_volume =
 | 
						|
						gus_read16(0x09) >> 4;	/* Get current volume */
 | 
						|
 | 
						|
	voices[voice].mode &= ~WAVE_SUSTAIN_ON;
 | 
						|
	gus_rampoff();
 | 
						|
	step_envelope(voice);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_voice_fade(int voice)
 | 
						|
{
 | 
						|
	int instr_no = sample_map[voice], is16bits;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
 | 
						|
	if (instr_no < 0 || instr_no > MAX_SAMPLE)
 | 
						|
	{
 | 
						|
		gus_write8(0x00, 0x03);	/* Hard stop */
 | 
						|
		voice_alloc->map[voice] = 0;
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 8 or 16 bits */
 | 
						|
 | 
						|
	if (voices[voice].mode & WAVE_ENVELOPES)
 | 
						|
	{
 | 
						|
		start_release(voice);
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * Ramp the volume down but not too quickly.
 | 
						|
	 */
 | 
						|
	if ((int) (gus_read16(0x09) >> 4) < 100)	/* Get current volume */
 | 
						|
	{
 | 
						|
		gus_voice_off();
 | 
						|
		gus_rampoff();
 | 
						|
		gus_voice_init(voice);
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	gus_ramp_range(65, 4030);
 | 
						|
	gus_ramp_rate(2, 4);
 | 
						|
	gus_rampon(0x40 | 0x20);	/* Down, once, with IRQ */
 | 
						|
	voices[voice].volume_irq_mode = VMODE_HALT;
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
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++)
 | 
						|
	{
 | 
						|
		gus_voice_init(i);	/* Turn voice off */
 | 
						|
		gus_voice_init2(i);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void gus_initialize(void)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	unsigned char dma_image, irq_image, tmp;
 | 
						|
 | 
						|
	static unsigned char gus_irq_map[16] = 	{
 | 
						|
		0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7
 | 
						|
	};
 | 
						|
 | 
						|
	static unsigned char gus_dma_map[8] = {
 | 
						|
		0, 1, 0, 2, 0, 3, 4, 5
 | 
						|
	};
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_write8(0x4c, 0);	/* Reset GF1 */
 | 
						|
	gus_delay();
 | 
						|
	gus_delay();
 | 
						|
 | 
						|
	gus_write8(0x4c, 1);	/* Release Reset */
 | 
						|
	gus_delay();
 | 
						|
	gus_delay();
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Clear all interrupts
 | 
						|
	 */
 | 
						|
 | 
						|
	gus_write8(0x41, 0);	/* DMA control */
 | 
						|
	gus_write8(0x45, 0);	/* Timer control */
 | 
						|
	gus_write8(0x49, 0);	/* Sample control */
 | 
						|
 | 
						|
	gus_select_max_voices(24);
 | 
						|
 | 
						|
	inb(u_Status);		/* Touch the status register */
 | 
						|
 | 
						|
	gus_look8(0x41);	/* Clear any pending DMA IRQs */
 | 
						|
	gus_look8(0x49);	/* Clear any pending sample IRQs */
 | 
						|
	gus_read8(0x0f);	/* Clear pending IRQs */
 | 
						|
 | 
						|
	gus_reset();		/* Resets all voices */
 | 
						|
 | 
						|
	gus_look8(0x41);	/* Clear any pending DMA IRQs */
 | 
						|
	gus_look8(0x49);	/* Clear any pending sample IRQs */
 | 
						|
	gus_read8(0x0f);	/* Clear pending IRQs */
 | 
						|
 | 
						|
	gus_write8(0x4c, 7);	/* Master reset | DAC enable | IRQ enable */
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Set up for Digital ASIC
 | 
						|
	 */
 | 
						|
 | 
						|
	outb((0x05), gus_base + 0x0f);
 | 
						|
 | 
						|
	mix_image |= 0x02;	/* Disable line out (for a moment) */
 | 
						|
	outb((mix_image), u_Mixer);
 | 
						|
 | 
						|
	outb((0x00), u_IRQDMAControl);
 | 
						|
 | 
						|
	outb((0x00), gus_base + 0x0f);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Now set up the DMA and IRQ interface
 | 
						|
	 *
 | 
						|
	 * The GUS supports two IRQs and two DMAs.
 | 
						|
	 *
 | 
						|
	 * 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];
 | 
						|
	if (!gus_pnp_flag && !tmp)
 | 
						|
		printk(KERN_WARNING "Warning! GUS IRQ not selected\n");
 | 
						|
	irq_image |= tmp;
 | 
						|
	irq_image |= 0x40;	/* Combine IRQ1 (GF1) and IRQ2 (Midi) */
 | 
						|
 | 
						|
	dual_dma_mode = 1;
 | 
						|
	if (gus_dma2 == gus_dma || gus_dma2 == -1)
 | 
						|
	{
 | 
						|
		dual_dma_mode = 0;
 | 
						|
		dma_image = 0x40;	/* Combine DMA1 (DRAM) and IRQ2 (ADC) */
 | 
						|
 | 
						|
		tmp = gus_dma_map[gus_dma];
 | 
						|
		if (!tmp)
 | 
						|
			printk(KERN_WARNING "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(KERN_WARNING "Warning! GUS DMA not selected\n");
 | 
						|
 | 
						|
		tmp = gus_dma_map[gus_dma2] << 3;
 | 
						|
		if (!tmp)
 | 
						|
		{
 | 
						|
			printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n");
 | 
						|
			tmp = 0x40;		/* Combine DMA channels */
 | 
						|
			    dual_dma_mode = 0;
 | 
						|
		}
 | 
						|
		dma_image |= tmp;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * For some reason the IRQ and DMA addresses must be written twice
 | 
						|
	 */
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Doing it first time
 | 
						|
	 */
 | 
						|
 | 
						|
	outb((mix_image), u_Mixer);	/* Select DMA control */
 | 
						|
	outb((dma_image | 0x80), u_IRQDMAControl);	/* Set DMA address */
 | 
						|
 | 
						|
	outb((mix_image | 0x40), u_Mixer);	/* Select IRQ control */
 | 
						|
	outb((irq_image), u_IRQDMAControl);	/* Set IRQ address */
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Doing it second time
 | 
						|
	 */
 | 
						|
 | 
						|
	outb((mix_image), u_Mixer);	/* Select DMA control */
 | 
						|
	outb((dma_image), u_IRQDMAControl);	/* Set DMA address */
 | 
						|
 | 
						|
	outb((mix_image | 0x40), u_Mixer);	/* Select IRQ control */
 | 
						|
	outb((irq_image), u_IRQDMAControl);	/* Set IRQ address */
 | 
						|
 | 
						|
	gus_select_voice(0);	/* This disables writes to IRQ/DMA reg */
 | 
						|
 | 
						|
	mix_image &= ~0x02;	/* Enable line out */
 | 
						|
	mix_image |= 0x08;	/* Enable IRQ */
 | 
						|
	outb((mix_image), u_Mixer);	/*
 | 
						|
					 * Turn mixer channels on
 | 
						|
					 * Note! Mic in is left off.
 | 
						|
					 */
 | 
						|
 | 
						|
	gus_select_voice(0);	/* This disables writes to IRQ/DMA reg */
 | 
						|
 | 
						|
	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
 | 
						|
 | 
						|
	inb(u_Status);		/* Touch the status register */
 | 
						|
 | 
						|
	gus_look8(0x41);	/* Clear any pending DMA IRQs */
 | 
						|
	gus_look8(0x49);	/* Clear any pending sample IRQs */
 | 
						|
 | 
						|
	gus_read8(0x0f);	/* Clear pending IRQs */
 | 
						|
 | 
						|
	if (iw_mode)
 | 
						|
		gus_write8(0x19, gus_read8(0x19) | 0x01);
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void __init pnp_mem_init(void)
 | 
						|
{
 | 
						|
#include "iwmem.h"
 | 
						|
#define CHUNK_SIZE (256*1024)
 | 
						|
#define BANK_SIZE (4*1024*1024)
 | 
						|
#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE)
 | 
						|
 | 
						|
	int bank, chunk, addr, total = 0;
 | 
						|
	int bank_sizes[4];
 | 
						|
	int i, j, bits = -1, testbits = -1, nbanks = 0;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * This routine determines what kind of RAM is installed in each of the four
 | 
						|
	 * SIMM banks and configures the DRAM address decode logic accordingly.
 | 
						|
	 */
 | 
						|
 | 
						|
	/*
 | 
						|
	 *    Place the chip into enhanced mode
 | 
						|
	 */
 | 
						|
	gus_write8(0x19, gus_read8(0x19) | 0x01);
 | 
						|
	gus_write8(0x53, gus_look8(0x53) & ~0x02);	/* Select DRAM I/O access */
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
 | 
						|
	 */
 | 
						|
 | 
						|
	gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Perform the DRAM size detection for each bank individually.
 | 
						|
	 */
 | 
						|
	for (bank = 0; bank < 4; bank++)
 | 
						|
	{
 | 
						|
		int size = 0;
 | 
						|
 | 
						|
		addr = bank * BANK_SIZE;
 | 
						|
 | 
						|
		/* Clean check points of each chunk */
 | 
						|
		for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
 | 
						|
		{
 | 
						|
			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
 | 
						|
			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Write a value to each chunk point and verify the result */
 | 
						|
		for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
 | 
						|
		{
 | 
						|
			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55);
 | 
						|
			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA);
 | 
						|
 | 
						|
			if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 &&
 | 
						|
				gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA)
 | 
						|
			{
 | 
						|
				/* OK. There is RAM. Now check for possible shadows */
 | 
						|
				int ok = 1, chunk2;
 | 
						|
 | 
						|
				for (chunk2 = 0; ok && chunk2 < chunk; chunk2++)
 | 
						|
					if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) ||
 | 
						|
							gus_peek(addr + chunk2 * CHUNK_SIZE + 1L))
 | 
						|
						ok = 0;	/* Addressing wraps */
 | 
						|
 | 
						|
				if (ok)
 | 
						|
					size = (chunk + 1) * CHUNK_SIZE;
 | 
						|
			}
 | 
						|
			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
 | 
						|
			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
 | 
						|
		}
 | 
						|
		bank_sizes[bank] = size;
 | 
						|
		if (size)
 | 
						|
			nbanks = bank + 1;
 | 
						|
		DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024));
 | 
						|
	}
 | 
						|
 | 
						|
	if (nbanks == 0)	/* No RAM - Give up */
 | 
						|
	{
 | 
						|
		printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n");
 | 
						|
		printk(KERN_ERR "Sound: Unable to work with this card.\n");
 | 
						|
		gus_write8(0x19, gus_read8(0x19) & ~0x01);
 | 
						|
		gus_mem_size = 0;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Now we know how much DRAM there is in each bank. The next step is
 | 
						|
	 * to find a DRAM size encoding (0 to 12) which is best for the combination
 | 
						|
	 * we have.
 | 
						|
	 *
 | 
						|
	 * First try if any of the possible alternatives matches exactly the amount
 | 
						|
	 * of memory we have.
 | 
						|
	 */
 | 
						|
 | 
						|
	for (i = 0; bits == -1 && i < 13; i++)
 | 
						|
	{
 | 
						|
		bits = i;
 | 
						|
 | 
						|
		for (j = 0; bits != -1 && j < 4; j++)
 | 
						|
			if (mem_decode[i][j] != bank_sizes[j])
 | 
						|
				bits = -1;	/* No hit */
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * If necessary, try to find a combination where other than the last
 | 
						|
	 * bank matches our configuration and the last bank is left oversized.
 | 
						|
	 * In this way we don't leave holes in the middle of memory.
 | 
						|
	 */
 | 
						|
 | 
						|
	if (bits == -1)		/* No luck yet */
 | 
						|
	{
 | 
						|
		for (i = 0; bits == -1 && i < 13; i++)
 | 
						|
		{
 | 
						|
			bits = i;
 | 
						|
 | 
						|
			for (j = 0; bits != -1 && j < nbanks - 1; j++)
 | 
						|
				if (mem_decode[i][j] != bank_sizes[j])
 | 
						|
					bits = -1;	/* No hit */
 | 
						|
			if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1])
 | 
						|
				bits = -1;	/* The last bank is too small */
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/*
 | 
						|
 	 * The last resort is to search for a combination where the banks are
 | 
						|
 	 * smaller than the actual SIMMs. This leaves some memory in the banks
 | 
						|
 	 * unused but doesn't leave holes in the DRAM address space.
 | 
						|
 	 */
 | 
						|
 	if (bits == -1)		/* No luck yet */
 | 
						|
 	{
 | 
						|
 		for (i = 0; i < 13; i++)
 | 
						|
 		{
 | 
						|
 			testbits = i;
 | 
						|
 			for (j = 0; testbits != -1 && j < nbanks - 1; j++)
 | 
						|
 				if (mem_decode[i][j] > bank_sizes[j]) {
 | 
						|
 					testbits = -1;
 | 
						|
 				}
 | 
						|
 			if(testbits > bits) bits = testbits;
 | 
						|
 		}
 | 
						|
 		if (bits != -1)
 | 
						|
 		{
 | 
						|
			printk(KERN_INFO "Interwave: Can't use all installed RAM.\n");
 | 
						|
			printk(KERN_INFO "Interwave: Try reordering SIMMS.\n");
 | 
						|
		}
 | 
						|
		printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n");
 | 
						|
		printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n");
 | 
						|
		bits = 0;
 | 
						|
	}
 | 
						|
	DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits));
 | 
						|
 | 
						|
	for (bank = 0; bank < 4; bank++)
 | 
						|
	{
 | 
						|
		DDB(printk("  Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024));
 | 
						|
 | 
						|
		if (bank_sizes[bank] > mem_decode[bits][bank])
 | 
						|
			total += mem_decode[bits][bank];
 | 
						|
		else
 | 
						|
			total += bank_sizes[bank];
 | 
						|
	}
 | 
						|
 | 
						|
	DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024));
 | 
						|
 | 
						|
	/*
 | 
						|
	 *    Set the memory addressing mode.
 | 
						|
	 */
 | 
						|
	gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits);
 | 
						|
 | 
						|
/*      Leave the chip into enhanced mode. Disable LFO  */
 | 
						|
	gus_mem_size = total;
 | 
						|
	iw_mode = 1;
 | 
						|
	gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02);
 | 
						|
}
 | 
						|
 | 
						|
int __init gus_wave_detect(int baseaddr)
 | 
						|
{
 | 
						|
	unsigned long   i, max_mem = 1024L;
 | 
						|
	unsigned long   loc;
 | 
						|
	unsigned char   val;
 | 
						|
 | 
						|
	if (!request_region(baseaddr, 16, "GUS"))
 | 
						|
		return 0;
 | 
						|
	if (!request_region(baseaddr + 0x100, 12, "GUS")) { /* 0x10c-> is MAX */
 | 
						|
		release_region(baseaddr, 16);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	gus_base = baseaddr;
 | 
						|
 | 
						|
	gus_write8(0x4c, 0);	/* Reset GF1 */
 | 
						|
	gus_delay();
 | 
						|
	gus_delay();
 | 
						|
 | 
						|
	gus_write8(0x4c, 1);	/* Release Reset */
 | 
						|
	gus_delay();
 | 
						|
	gus_delay();
 | 
						|
 | 
						|
#ifdef GUSPNP_AUTODETECT
 | 
						|
	val = gus_look8(0x5b);	/* Version number register */
 | 
						|
	gus_write8(0x5b, ~val);	/* Invert all bits */
 | 
						|
 | 
						|
	if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0))	/* No change */
 | 
						|
	{
 | 
						|
		if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f))	/* Change */
 | 
						|
		{
 | 
						|
			DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
 | 
						|
			gus_pnp_flag = 1;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b)));
 | 
						|
			gus_pnp_flag = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	gus_write8(0x5b, val);	/* Restore all bits */
 | 
						|
#endif
 | 
						|
 | 
						|
	if (gus_pnp_flag)
 | 
						|
		pnp_mem_init();
 | 
						|
	if (iw_mode)
 | 
						|
		return 1;
 | 
						|
 | 
						|
	/* See if there is first block there.... */
 | 
						|
	gus_poke(0L, 0xaa);
 | 
						|
	if (gus_peek(0L) != 0xaa) {
 | 
						|
		release_region(baseaddr + 0x100, 12);
 | 
						|
		release_region(baseaddr, 16);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Now zero it out so that I can check for mirroring .. */
 | 
						|
	gus_poke(0L, 0x00);
 | 
						|
	for (i = 1L; i < max_mem; i++)
 | 
						|
	{
 | 
						|
		int n, failed;
 | 
						|
 | 
						|
		/* check for mirroring ... */
 | 
						|
		if (gus_peek(0L) != 0)
 | 
						|
			break;
 | 
						|
		loc = i << 10;
 | 
						|
 | 
						|
		for (n = loc - 1, failed = 0; n <= loc; n++)
 | 
						|
		{
 | 
						|
			gus_poke(loc, 0xaa);
 | 
						|
			if (gus_peek(loc) != 0xaa)
 | 
						|
				failed = 1;
 | 
						|
			gus_poke(loc, 0x55);
 | 
						|
			if (gus_peek(loc) != 0x55)
 | 
						|
				failed = 1;
 | 
						|
		}
 | 
						|
		if (failed)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	gus_mem_size = i << 10;
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
static int guswave_ioctl(int dev, unsigned int cmd, void __user *arg)
 | 
						|
{
 | 
						|
 | 
						|
	switch (cmd) 
 | 
						|
	{
 | 
						|
		case SNDCTL_SYNTH_INFO:
 | 
						|
			gus_info.nr_voices = nr_voices;
 | 
						|
			if (copy_to_user(arg, &gus_info, sizeof(gus_info)))
 | 
						|
				return -EFAULT;
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case SNDCTL_SEQ_RESETSAMPLES:
 | 
						|
			reset_sample_memory();
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case SNDCTL_SEQ_PERCMODE:
 | 
						|
			return 0;
 | 
						|
 | 
						|
		case SNDCTL_SYNTH_MEMAVL:
 | 
						|
			return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
 | 
						|
 | 
						|
		default:
 | 
						|
			return -EINVAL;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int guswave_set_instr(int dev, int voice, int instr_no)
 | 
						|
{
 | 
						|
	int sample_no;
 | 
						|
 | 
						|
	if (instr_no < 0 || instr_no > MAX_PATCH)
 | 
						|
		instr_no = 0;	/* Default to acoustic piano */
 | 
						|
 | 
						|
	if (voice < 0 || voice > 31)
 | 
						|
		return -EINVAL;
 | 
						|
 | 
						|
	if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
 | 
						|
	{
 | 
						|
		voices[voice].sample_pending = instr_no;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	sample_no = patch_table[instr_no];
 | 
						|
	patch_map[voice] = -1;
 | 
						|
 | 
						|
	if (sample_no == NOT_SAMPLE)
 | 
						|
	{
 | 
						|
/*		printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/
 | 
						|
		return -EINVAL;	/* Patch not defined */
 | 
						|
	}
 | 
						|
	if (sample_ptrs[sample_no] == -1)	/* Sample not loaded */
 | 
						|
	{
 | 
						|
/*		printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	sample_map[voice] = sample_no;
 | 
						|
	patch_map[voice] = instr_no;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int guswave_kill_note(int dev, int voice, int note, int velocity)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	/* voice_alloc->map[voice] = 0xffff; */
 | 
						|
	if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
 | 
						|
	{
 | 
						|
		voices[voice].kill_pending = 1;
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		gus_voice_fade(voice);
 | 
						|
	}
 | 
						|
 | 
						|
	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;
 | 
						|
}
 | 
						|
 | 
						|
static void guswave_volume_method(int dev, int mode)
 | 
						|
{
 | 
						|
	if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
 | 
						|
		volume_method = mode;
 | 
						|
}
 | 
						|
 | 
						|
static void compute_volume(int voice, int volume)
 | 
						|
{
 | 
						|
	if (volume < 128)
 | 
						|
		voices[voice].midi_volume = volume;
 | 
						|
 | 
						|
	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;
 | 
						|
 | 
						|
		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);
 | 
						|
	}
 | 
						|
 | 
						|
	if (voices[voice].initial_volume > 4030)
 | 
						|
		voices[voice].initial_volume = 4030;
 | 
						|
}
 | 
						|
 | 
						|
static void compute_and_set_volume(int voice, int volume, int ramp_time)
 | 
						|
{
 | 
						|
	int curr, target, rate;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	compute_volume(voice, volume);
 | 
						|
	voices[voice].current_volume = voices[voice].initial_volume;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	/*
 | 
						|
	 * CAUTION! Interrupts disabled. Enable them before returning
 | 
						|
	 */
 | 
						|
 | 
						|
	gus_select_voice(voice);
 | 
						|
 | 
						|
	curr = gus_read16(0x09) >> 4;
 | 
						|
	target = voices[voice].initial_volume;
 | 
						|
 | 
						|
	if (ramp_time == INSTANT_RAMP)
 | 
						|
	{
 | 
						|
		gus_rampoff();
 | 
						|
		gus_voice_volume(target);
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	if (ramp_time == FAST_RAMP)
 | 
						|
		rate = 63;
 | 
						|
	else
 | 
						|
		rate = 16;
 | 
						|
	gus_ramp_rate(0, rate);
 | 
						|
 | 
						|
	if ((target - curr) / 64 == 0)	/* Close enough to target. */
 | 
						|
	{
 | 
						|
		gus_rampoff();
 | 
						|
		gus_voice_volume(target);
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	if (target > curr)
 | 
						|
	{
 | 
						|
		if (target > (4095 - 65))
 | 
						|
			target = 4095 - 65;
 | 
						|
		gus_ramp_range(curr, target);
 | 
						|
		gus_rampon(0x00);	/* Ramp up, once, no IRQ */
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (target < 65)
 | 
						|
			target = 65;
 | 
						|
 | 
						|
		gus_ramp_range(target, curr);
 | 
						|
		gus_rampon(0x40);	/* Ramp down, once, no irq */
 | 
						|
	}
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
static void dynamic_volume_change(int voice)
 | 
						|
{
 | 
						|
	unsigned char status;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
	status = gus_read8(0x00);	/* Get voice status */
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
 | 
						|
	if (status & 0x03)
 | 
						|
		return;		/* Voice was not running */
 | 
						|
 | 
						|
	if (!(voices[voice].mode & WAVE_ENVELOPES))
 | 
						|
	{
 | 
						|
		compute_and_set_volume(voice, voices[voice].midi_volume, 1);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	
 | 
						|
	/*
 | 
						|
	 * Voice is running and has envelopes.
 | 
						|
	 */
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
	status = gus_read8(0x0d);	/* Ramping status */
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
 | 
						|
	if (status & 0x03)	/* Sustain phase? */
 | 
						|
	{
 | 
						|
		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;
 | 
						|
 | 
						|
			if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
 | 
						|
			{
 | 
						|
				freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0);
 | 
						|
				voices[voice].current_freq = freq;
 | 
						|
 | 
						|
				spin_lock_irqsave(&gus_lock,flags);
 | 
						|
				gus_select_voice(voice);
 | 
						|
				gus_voice_freq(freq);
 | 
						|
				spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case CTRL_PITCH_BENDER_RANGE:
 | 
						|
			voices[voice].bender_range = value;
 | 
						|
			break;
 | 
						|
		case CTL_EXPRESSION:
 | 
						|
			value /= 128;
 | 
						|
		case CTRL_EXPRESSION:
 | 
						|
			if (volume_method == VOL_METHOD_ADAGIO)
 | 
						|
			{
 | 
						|
				voices[voice].expression_vol = value;
 | 
						|
				if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
 | 
						|
					dynamic_volume_change(voice);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case CTL_PAN:
 | 
						|
			voices[voice].panning = (value * 2) - 128;
 | 
						|
			break;
 | 
						|
 | 
						|
		case CTL_MAIN_VOLUME:
 | 
						|
			value = (value * 100) / 16383;
 | 
						|
 | 
						|
		case CTRL_MAIN_VOLUME:
 | 
						|
			voices[voice].main_vol = value;
 | 
						|
			if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
 | 
						|
				dynamic_volume_change(voice);
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int guswave_start_note2(int dev, int voice, int note_num, int volume)
 | 
						|
{
 | 
						|
	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");*/
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	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)
 | 
						|
		return -EINVAL;
 | 
						|
	if ((samplep = patch_table[patch]) == NOT_SAMPLE)
 | 
						|
	{
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	note_freq = note_to_freq(note_num);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * 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;
 | 
						|
	while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1)
 | 
						|
	{
 | 
						|
		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;
 | 
						|
		}
 | 
						|
		if (samples[samplep].low_note <= note_freq &&
 | 
						|
			note_freq <= samples[samplep].high_note)
 | 
						|
		{
 | 
						|
			sample = samplep;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			samplep = samples[samplep].key;	/* Link to next sample */
 | 
						|
	  }
 | 
						|
	if (sample == -1)
 | 
						|
		sample = best_sample;
 | 
						|
 | 
						|
	if (sample == -1)
 | 
						|
	{
 | 
						|
/*		printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/
 | 
						|
		return 0;	/* Should play default patch ??? */
 | 
						|
	}
 | 
						|
	is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
 | 
						|
	voices[voice].mode = samples[sample].mode;
 | 
						|
	voices[voice].patch_vol = samples[sample].volume;
 | 
						|
 | 
						|
	if (iw_mode)
 | 
						|
		gus_write8(0x15, 0x00);		/* RAM, Reset voice deactivate bit of SMSI */
 | 
						|
 | 
						|
	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;
 | 
						|
 | 
						|
	if (voices[voice].fixed_pitch)	/* Fixed pitch */
 | 
						|
	{
 | 
						|
		  freq = samples[sample].base_freq;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		base_note = samples[sample].base_note / 100;
 | 
						|
		note_freq /= 100;
 | 
						|
 | 
						|
		freq = samples[sample].base_freq * note_freq / base_note;
 | 
						|
	}
 | 
						|
 | 
						|
	voices[voice].orig_freq = freq;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Since the pitch bender may have been set before playing the note, we
 | 
						|
	 * have to calculate the bending now.
 | 
						|
	 */
 | 
						|
 | 
						|
	freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender,
 | 
						|
				voices[voice].bender_range, 0);
 | 
						|
	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)
 | 
						|
	{
 | 
						|
		mode |= 0x04;	/* 16 bits */
 | 
						|
		if ((sample_ptrs[sample] / GUS_BANK_SIZE) !=
 | 
						|
			((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))
 | 
						|
				printk(KERN_ERR "GUS: Sample address error\n");
 | 
						|
	}
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
	gus_voice_off();
 | 
						|
	gus_rampoff();
 | 
						|
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
 | 
						|
	if (voices[voice].mode & WAVE_ENVELOPES)
 | 
						|
	{
 | 
						|
		compute_volume(voice, volume);
 | 
						|
		init_envelope(voice);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		compute_and_set_volume(voice, volume, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
 | 
						|
	if (samples[sample].mode & WAVE_LOOP_BACK)
 | 
						|
		gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -
 | 
						|
			voices[voice].offset_pending, 0, is16bits);	/* start=end */
 | 
						|
	else
 | 
						|
		gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits);	/* Sample start=begin */
 | 
						|
 | 
						|
	if (samples[sample].mode & WAVE_LOOPING)
 | 
						|
	{
 | 
						|
		mode |= 0x08;
 | 
						|
 | 
						|
		if (samples[sample].mode & WAVE_BIDIR_LOOP)
 | 
						|
			mode |= 0x10;
 | 
						|
 | 
						|
		if (samples[sample].mode & WAVE_LOOP_BACK)
 | 
						|
		{
 | 
						|
			gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end -
 | 
						|
					   voices[voice].offset_pending,
 | 
						|
					   (samples[sample].fractions >> 4) & 0x0f, is16bits);
 | 
						|
			mode |= 0x40;
 | 
						|
		}
 | 
						|
		gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start,
 | 
						|
			samples[sample].fractions & 0x0f, is16bits);	/* Loop start location */
 | 
						|
		gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end,
 | 
						|
			(samples[sample].fractions >> 4) & 0x0f, is16bits);	/* Loop end location */
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		mode |= 0x20;	/* Loop IRQ at the end */
 | 
						|
		voices[voice].loop_irq_mode = LMODE_FINISH;	/* Ramp down at the end */
 | 
						|
		voices[voice].loop_irq_parm = 1;
 | 
						|
		gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits);	/* Loop start location */
 | 
						|
		gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1,
 | 
						|
			(samples[sample].fractions >> 4) & 0x0f, is16bits);	/* Loop end location */
 | 
						|
	}
 | 
						|
	gus_voice_freq(freq);
 | 
						|
	gus_voice_balance(pan);
 | 
						|
	gus_voice_on(mode);
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
 | 
						|
static int guswave_start_note(int dev, int voice, int note_num, int volume)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	int mode;
 | 
						|
	int ret_val = 0;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	if (note_num == 255)
 | 
						|
	{
 | 
						|
		if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
 | 
						|
		{
 | 
						|
			voices[voice].volume_pending = volume;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			ret_val = guswave_start_note2(dev, voice, note_num, volume);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		gus_select_voice(voice);
 | 
						|
		mode = gus_read8(0x00);
 | 
						|
		if (mode & 0x20)
 | 
						|
			gus_write8(0x00, mode & 0xdf);	/* No interrupt! */
 | 
						|
 | 
						|
		voices[voice].offset_pending = 0;
 | 
						|
		voices[voice].kill_pending = 0;
 | 
						|
		voices[voice].volume_irq_mode = 0;
 | 
						|
		voices[voice].loop_irq_mode = 0;
 | 
						|
 | 
						|
		if (voices[voice].sample_pending >= 0)
 | 
						|
		{
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);	/* Run temporarily with interrupts enabled */
 | 
						|
			guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending);
 | 
						|
			voices[voice].sample_pending = -1;
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);	/* Reselect the voice (just to be sure) */
 | 
						|
		}
 | 
						|
		if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065))
 | 
						|
		{
 | 
						|
			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);
 | 
						|
			gus_ramp_rate(0, 63);	/* Fastest possible rate */
 | 
						|
			gus_rampon(0x20 | 0x40);	/* Ramp down, once, irq */
 | 
						|
		}
 | 
						|
	}
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
	return ret_val;
 | 
						|
}
 | 
						|
 | 
						|
static void guswave_reset(int dev)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < 32; i++)
 | 
						|
	{
 | 
						|
		gus_voice_init(i);
 | 
						|
		gus_voice_init2(i);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int guswave_open(int dev, int mode)
 | 
						|
{
 | 
						|
	int err;
 | 
						|
 | 
						|
	if (gus_busy)
 | 
						|
		return -EBUSY;
 | 
						|
 | 
						|
	voice_alloc->timestamp = 0;
 | 
						|
 | 
						|
	if (gus_no_wave_dma) {
 | 
						|
		gus_no_dma = 1;
 | 
						|
	} else {
 | 
						|
		if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
 | 
						|
		{
 | 
						|
			/* printk( "GUS: Loading samples without DMA\n"); */
 | 
						|
			gus_no_dma = 1;	/* Upload samples using PIO */
 | 
						|
		}
 | 
						|
		else
 | 
						|
			gus_no_dma = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	init_waitqueue_head(&dram_sleeper);
 | 
						|
	gus_busy = 1;
 | 
						|
	active_device = GUS_DEV_WAVE;
 | 
						|
 | 
						|
	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
 | 
						|
	gus_initialize();
 | 
						|
	gus_reset();
 | 
						|
	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void guswave_close(int dev)
 | 
						|
{
 | 
						|
	gus_busy = 0;
 | 
						|
	active_device = 0;
 | 
						|
	gus_reset();
 | 
						|
 | 
						|
	if (!gus_no_dma)
 | 
						|
		DMAbuf_close_dma(gus_devnum);
 | 
						|
}
 | 
						|
 | 
						|
static int guswave_load_patch(int dev, int format, const char __user *addr,
 | 
						|
		   int offs, int count, int pmgr_flag)
 | 
						|
{
 | 
						|
	struct patch_info patch;
 | 
						|
	int instr;
 | 
						|
	long sizeof_patch;
 | 
						|
 | 
						|
	unsigned long blk_sz, blk_end, left, src_offs, target;
 | 
						|
 | 
						|
	sizeof_patch = (long) &patch.data[0] - (long) &patch;	/* Header size */
 | 
						|
 | 
						|
	if (format != GUS_PATCH)
 | 
						|
	{
 | 
						|
/*		printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	if (count < sizeof_patch)
 | 
						|
	{
 | 
						|
/*		  printk("GUS Error: Patch header too short\n");*/
 | 
						|
		  return -EINVAL;
 | 
						|
	}
 | 
						|
	count -= sizeof_patch;
 | 
						|
 | 
						|
	if (free_sample >= MAX_SAMPLE)
 | 
						|
	{
 | 
						|
/*		  printk("GUS: Sample table full\n");*/
 | 
						|
		  return -ENOSPC;
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * Copy the header from user space but ignore the first bytes which have
 | 
						|
	 * been transferred already.
 | 
						|
	 */
 | 
						|
 | 
						|
	if (copy_from_user(&((char *) &patch)[offs], &(addr)[offs],
 | 
						|
			   sizeof_patch - offs))
 | 
						|
		return -EFAULT;
 | 
						|
 | 
						|
	if (patch.mode & WAVE_ROM)
 | 
						|
		return -EINVAL;
 | 
						|
	if (gus_mem_size == 0)
 | 
						|
		return -ENOSPC;
 | 
						|
 | 
						|
	instr = patch.instr_no;
 | 
						|
 | 
						|
	if (instr < 0 || instr > MAX_PATCH)
 | 
						|
	{
 | 
						|
/*		printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	if (count < patch.len)
 | 
						|
	{
 | 
						|
/*		printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/
 | 
						|
		patch.len = count;
 | 
						|
	}
 | 
						|
	if (patch.len <= 0 || patch.len > gus_mem_size)
 | 
						|
	{
 | 
						|
/*		printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	if (patch.mode & WAVE_LOOPING)
 | 
						|
	{
 | 
						|
		if (patch.loop_start < 0 || patch.loop_start >= patch.len)
 | 
						|
		{
 | 
						|
/*			printk(KERN_ERR "GUS: Invalid loop start\n");*/
 | 
						|
			return -EINVAL;
 | 
						|
		}
 | 
						|
		if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
 | 
						|
		{
 | 
						|
/*			printk(KERN_ERR "GUS: Invalid loop end\n");*/
 | 
						|
			return -EINVAL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	free_mem_ptr = (free_mem_ptr + 31) & ~31;	/* 32 byte alignment */
 | 
						|
 | 
						|
	if (patch.mode & WAVE_16_BITS)
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 * 16 bit samples must fit one 256k bank.
 | 
						|
		 */
 | 
						|
		if (patch.len >= GUS_BANK_SIZE)
 | 
						|
		{
 | 
						|
/*			 printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/
 | 
						|
			return -ENOSPC;
 | 
						|
		}
 | 
						|
		if ((free_mem_ptr / GUS_BANK_SIZE) !=
 | 
						|
			((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
 | 
						|
		{
 | 
						|
			unsigned long   tmp_mem =	
 | 
						|
				/* Align to 256K */
 | 
						|
					((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
 | 
						|
 | 
						|
			if ((tmp_mem + patch.len) > gus_mem_size)
 | 
						|
				return -ENOSPC;
 | 
						|
 | 
						|
			free_mem_ptr = tmp_mem;		/* This leaves unusable memory */
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if ((free_mem_ptr + patch.len) > gus_mem_size)
 | 
						|
		return -ENOSPC;
 | 
						|
 | 
						|
	sample_ptrs[free_sample] = free_mem_ptr;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Tremolo is not possible with envelopes
 | 
						|
	 */
 | 
						|
 | 
						|
	if (patch.mode & WAVE_ENVELOPES)
 | 
						|
		patch.mode &= ~WAVE_TREMOLO;
 | 
						|
 | 
						|
	if (!(patch.mode & WAVE_FRACTIONS))
 | 
						|
	{
 | 
						|
		  patch.fractions = 0;
 | 
						|
	}
 | 
						|
	memcpy((char *) &samples[free_sample], &patch, sizeof_patch);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Link this_one sample to the list of samples for patch 'instr'.
 | 
						|
	 */
 | 
						|
 | 
						|
	samples[free_sample].key = patch_table[instr];
 | 
						|
	patch_table[instr] = free_sample;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Use DMA to transfer the wave data to the DRAM
 | 
						|
	 */
 | 
						|
 | 
						|
	left = patch.len;
 | 
						|
	src_offs = 0;
 | 
						|
	target = free_mem_ptr;
 | 
						|
 | 
						|
	while (left)		/* Not completely transferred yet */
 | 
						|
	{
 | 
						|
		blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
 | 
						|
		if (blk_sz > left)
 | 
						|
			blk_sz = left;
 | 
						|
 | 
						|
		/*
 | 
						|
		 * DMA cannot cross bank (256k) boundaries. Check for that.
 | 
						|
		 */
 | 
						|
		 
 | 
						|
		blk_end = target + blk_sz;
 | 
						|
 | 
						|
		if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE))
 | 
						|
		{
 | 
						|
			/* Split the block */
 | 
						|
			blk_end &= ~(GUS_BANK_SIZE - 1);
 | 
						|
			blk_sz = blk_end - target;
 | 
						|
		}
 | 
						|
		if (gus_no_dma)
 | 
						|
		{
 | 
						|
			/*
 | 
						|
			 * For some reason the DMA is not possible. We have to use PIO.
 | 
						|
			 */
 | 
						|
			long i;
 | 
						|
			unsigned char data;
 | 
						|
 | 
						|
			for (i = 0; i < blk_sz; i++)
 | 
						|
			{
 | 
						|
				get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[sizeof_patch + i]));
 | 
						|
				if (patch.mode & WAVE_UNSIGNED)
 | 
						|
					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;
 | 
						|
 | 
						|
			if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)
 | 
						|
			{
 | 
						|
				printk(KERN_ERR "GUS: DMA buffer == NULL\n");
 | 
						|
				return -ENOSPC;
 | 
						|
			}
 | 
						|
			/*
 | 
						|
			 * OK, move now. First in and then out.
 | 
						|
			 */
 | 
						|
 | 
						|
			if (copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf,
 | 
						|
					   &(addr)[sizeof_patch + src_offs],
 | 
						|
					   blk_sz))
 | 
						|
				return -EFAULT;
 | 
						|
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_write8(0x41, 0);	/* Disable GF1 DMA */
 | 
						|
			DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
 | 
						|
				blk_sz, DMA_MODE_WRITE);
 | 
						|
 | 
						|
			/*
 | 
						|
			 * Set the DRAM address for the wave data
 | 
						|
			 */
 | 
						|
 | 
						|
			if (iw_mode)
 | 
						|
			{
 | 
						|
				/* Different address translation in enhanced mode */
 | 
						|
 | 
						|
				unsigned char   hi;
 | 
						|
 | 
						|
				if (gus_dma > 4)
 | 
						|
					address = target >> 1;	/* Convert to 16 bit word address */
 | 
						|
				else
 | 
						|
					address = target;
 | 
						|
 | 
						|
				hi = (unsigned char) ((address >> 16) & 0xf0);
 | 
						|
				hi += (unsigned char) (address & 0x0f);
 | 
						|
 | 
						|
				gus_write16(0x42, (address >> 4) & 0xffff);	/* DMA address (low) */
 | 
						|
				gus_write8(0x50, hi);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				address = target;
 | 
						|
				if (audio_devs[gus_devnum]->dmap_out->dma > 3)
 | 
						|
				{
 | 
						|
					hold_address = address;
 | 
						|
					address = address >> 1;
 | 
						|
					address &= 0x0001ffffL;
 | 
						|
					address |= (hold_address & 0x000c0000L);
 | 
						|
				}
 | 
						|
				gus_write16(0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
 | 
						|
			}
 | 
						|
 | 
						|
			/*
 | 
						|
			 * Start the DMA transfer
 | 
						|
			 */
 | 
						|
 | 
						|
			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_ */
 | 
						|
			if (audio_devs[gus_devnum]->dmap_out->dma > 3)
 | 
						|
				dma_command |= 0x04;	/* 16 bit DMA _channel_ */
 | 
						|
			
 | 
						|
			/*
 | 
						|
			 * Sleep here until the DRAM DMA done interrupt is served
 | 
						|
			 */
 | 
						|
			active_device = GUS_DEV_WAVE;
 | 
						|
			gus_write8(0x41, dma_command);	/* Lets go luteet (=bugs) */
 | 
						|
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags); /* opens a race */
 | 
						|
			if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
 | 
						|
				printk("GUS: DMA Transfer timed out\n");
 | 
						|
		}
 | 
						|
 | 
						|
		/*
 | 
						|
		 * Now the next part
 | 
						|
		 */
 | 
						|
 | 
						|
		left -= blk_sz;
 | 
						|
		src_offs += blk_sz;
 | 
						|
		target += blk_sz;
 | 
						|
 | 
						|
		gus_write8(0x41, 0);	/* Stop DMA */
 | 
						|
	}
 | 
						|
 | 
						|
	free_mem_ptr += patch.len;
 | 
						|
	free_sample++;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void guswave_hw_control(int dev, unsigned char *event_rec)
 | 
						|
{
 | 
						|
	int voice, cmd;
 | 
						|
	unsigned short p1, p2;
 | 
						|
	unsigned int plong;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	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];
 | 
						|
 | 
						|
	if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
 | 
						|
		(cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
 | 
						|
		do_volume_irq(voice);
 | 
						|
 | 
						|
	switch (cmd)
 | 
						|
	{
 | 
						|
		case _GUS_NUMVOICES:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_select_max_voices(p1);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICESAMPLE:
 | 
						|
			guswave_set_instr(dev, voice, p1);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEON:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			p1 &= ~0x20;	/* Don't allow interrupts */
 | 
						|
			gus_voice_on(p1);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEOFF:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_voice_off();
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEFADE:
 | 
						|
			gus_voice_fade(voice);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEMODE:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			p1 &= ~0x20;	/* Don't allow interrupts */
 | 
						|
			gus_voice_mode(p1);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEBALA:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_voice_balance(p1);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEFREQ:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_voice_freq(plong);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEVOL:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_voice_volume(p1);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICEVOL2:	/* Just update the software voice level */
 | 
						|
			voices[voice].initial_volume = voices[voice].current_volume = p1;
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_RAMPRANGE:
 | 
						|
			if (voices[voice].mode & WAVE_ENVELOPES)
 | 
						|
				break;	/* NO-NO */
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_ramp_range(p1, p2);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_RAMPRATE:
 | 
						|
			if (voices[voice].mode & WAVE_ENVELOPES)
 | 
						|
				break;	/* NJET-NJET */
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_ramp_rate(p1, p2);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_RAMPMODE:
 | 
						|
			if (voices[voice].mode & WAVE_ENVELOPES)
 | 
						|
				break;	/* NO-NO */
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			p1 &= ~0x20;	/* Don't allow interrupts */
 | 
						|
			gus_ramp_mode(p1);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_RAMPON:
 | 
						|
			if (voices[voice].mode & WAVE_ENVELOPES)
 | 
						|
				break;	/* EI-EI */
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			p1 &= ~0x20;	/* Don't allow interrupts */
 | 
						|
			gus_rampon(p1);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_RAMPOFF:
 | 
						|
			if (voices[voice].mode & WAVE_ENVELOPES)
 | 
						|
				break;	/* NEJ-NEJ */
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_rampoff();
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOLUME_SCALE:
 | 
						|
			volume_base = p1;
 | 
						|
			volume_scale = p2;
 | 
						|
			break;
 | 
						|
 | 
						|
		case _GUS_VOICE_POS:
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_set_voice_pos(voice, plong);
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int gus_audio_set_speed(int speed)
 | 
						|
{
 | 
						|
	if (speed <= 0)
 | 
						|
		speed = gus_audio_speed;
 | 
						|
 | 
						|
	if (speed < 4000)
 | 
						|
		speed = 4000;
 | 
						|
 | 
						|
	if (speed > 44100)
 | 
						|
		speed = 44100;
 | 
						|
 | 
						|
	gus_audio_speed = speed;
 | 
						|
 | 
						|
	if (only_read_access)
 | 
						|
	{
 | 
						|
		/* Compute nearest valid recording speed  and return it */
 | 
						|
 | 
						|
		/* speed = (9878400 / (gus_audio_speed + 2)) / 16; */
 | 
						|
		speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
 | 
						|
		speed = (9878400 / (speed * 16)) - 2;
 | 
						|
	}
 | 
						|
	return speed;
 | 
						|
}
 | 
						|
 | 
						|
static int gus_audio_set_channels(int channels)
 | 
						|
{
 | 
						|
	if (!channels)
 | 
						|
		return gus_audio_channels;
 | 
						|
	if (channels > 2)
 | 
						|
		channels = 2;
 | 
						|
	if (channels < 1)
 | 
						|
		channels = 1;
 | 
						|
	gus_audio_channels = channels;
 | 
						|
	return channels;
 | 
						|
}
 | 
						|
 | 
						|
static int gus_audio_set_bits(int bits)
 | 
						|
{
 | 
						|
	if (!bits)
 | 
						|
		return gus_audio_bits;
 | 
						|
 | 
						|
	if (bits != 8 && bits != 16)
 | 
						|
		bits = 8;
 | 
						|
 | 
						|
	if (only_8_bits)
 | 
						|
		bits = 8;
 | 
						|
 | 
						|
	gus_audio_bits = bits;
 | 
						|
	return bits;
 | 
						|
}
 | 
						|
 | 
						|
static int gus_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
 | 
						|
{
 | 
						|
	int val;
 | 
						|
 | 
						|
	switch (cmd) 
 | 
						|
	{
 | 
						|
		case SOUND_PCM_WRITE_RATE:
 | 
						|
			if (get_user(val, (int __user*)arg))
 | 
						|
				return -EFAULT;
 | 
						|
			val = gus_audio_set_speed(val);
 | 
						|
			break;
 | 
						|
 | 
						|
		case SOUND_PCM_READ_RATE:
 | 
						|
			val = gus_audio_speed;
 | 
						|
			break;
 | 
						|
 | 
						|
		case SNDCTL_DSP_STEREO:
 | 
						|
			if (get_user(val, (int __user *)arg))
 | 
						|
				return -EFAULT;
 | 
						|
			val = gus_audio_set_channels(val + 1) - 1;
 | 
						|
			break;
 | 
						|
 | 
						|
		case SOUND_PCM_WRITE_CHANNELS:
 | 
						|
			if (get_user(val, (int __user *)arg))
 | 
						|
				return -EFAULT;
 | 
						|
			val = gus_audio_set_channels(val);
 | 
						|
			break;
 | 
						|
 | 
						|
		case SOUND_PCM_READ_CHANNELS:
 | 
						|
			val = gus_audio_channels;
 | 
						|
			break;
 | 
						|
		
 | 
						|
		case SNDCTL_DSP_SETFMT:
 | 
						|
			if (get_user(val, (int __user *)arg))
 | 
						|
				return -EFAULT;
 | 
						|
			val = gus_audio_set_bits(val);
 | 
						|
			break;
 | 
						|
		
 | 
						|
		case SOUND_PCM_READ_BITS:
 | 
						|
			val = gus_audio_bits;
 | 
						|
			break;
 | 
						|
		
 | 
						|
		case SOUND_PCM_WRITE_FILTER:		/* NOT POSSIBLE */
 | 
						|
		case SOUND_PCM_READ_FILTER:
 | 
						|
			val = -EINVAL;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			return -EINVAL;
 | 
						|
	}
 | 
						|
	return put_user(val, (int __user *)arg);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_audio_reset(int dev)
 | 
						|
{
 | 
						|
	if (recording_active)
 | 
						|
	{
 | 
						|
		gus_write8(0x49, 0x00);	/* Halt recording */
 | 
						|
		set_input_volumes();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int saved_iw_mode;	/* A hack hack hack */
 | 
						|
 | 
						|
static int gus_audio_open(int dev, int mode)
 | 
						|
{
 | 
						|
	if (gus_busy)
 | 
						|
		return -EBUSY;
 | 
						|
 | 
						|
	if (gus_pnp_flag && mode & OPEN_READ)
 | 
						|
	{
 | 
						|
/*		printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/
 | 
						|
		return -EIO;
 | 
						|
	}
 | 
						|
	gus_initialize();
 | 
						|
 | 
						|
	gus_busy = 1;
 | 
						|
	active_device = 0;
 | 
						|
 | 
						|
	saved_iw_mode = iw_mode;
 | 
						|
	if (iw_mode)
 | 
						|
	{
 | 
						|
		/* There are some problems with audio in enhanced mode so disable it */
 | 
						|
		gus_write8(0x19, gus_read8(0x19) & ~0x01);	/* Disable enhanced mode */
 | 
						|
		iw_mode = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	gus_reset();
 | 
						|
	reset_sample_memory();
 | 
						|
	gus_select_max_voices(14);
 | 
						|
 | 
						|
	pcm_active = 0;
 | 
						|
	dma_active = 0;
 | 
						|
	pcm_opened = 1;
 | 
						|
	if (mode & OPEN_READ)
 | 
						|
	{
 | 
						|
		recording_active = 1;
 | 
						|
		set_input_volumes();
 | 
						|
	}
 | 
						|
	only_read_access = !(mode & OPEN_WRITE);
 | 
						|
	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;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void gus_audio_close(int dev)
 | 
						|
{
 | 
						|
	iw_mode = saved_iw_mode;
 | 
						|
	gus_reset();
 | 
						|
	gus_busy = 0;
 | 
						|
	pcm_opened = 0;
 | 
						|
	active_device = 0;
 | 
						|
 | 
						|
	if (recording_active)
 | 
						|
	{
 | 
						|
		gus_write8(0x49, 0x00);	/* Halt recording */
 | 
						|
		set_input_volumes();
 | 
						|
	}
 | 
						|
	recording_active = 0;
 | 
						|
}
 | 
						|
 | 
						|
static void gus_audio_update_volume(void)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	int voice;
 | 
						|
 | 
						|
	if (pcm_active && pcm_opened)
 | 
						|
		for (voice = 0; voice < gus_audio_channels; voice++)
 | 
						|
		{
 | 
						|
			spin_lock_irqsave(&gus_lock,flags);
 | 
						|
			gus_select_voice(voice);
 | 
						|
			gus_rampoff();
 | 
						|
			gus_voice_volume(1530 + (25 * gus_pcm_volume));
 | 
						|
			gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
static void play_next_pcm_block(void)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	int speed = gus_audio_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_audio_channels; chn++)
 | 
						|
	{
 | 
						|
		mode[chn] = 0x00;
 | 
						|
		ramp_mode[chn] = 0x03;	/* Ramping and rollover off */
 | 
						|
 | 
						|
		if (chn == 0)
 | 
						|
		{
 | 
						|
			mode[chn] |= 0x20;	/* Loop IRQ */
 | 
						|
			voices[chn].loop_irq_mode = LMODE_PCM;
 | 
						|
		}
 | 
						|
		if (gus_audio_bits != 8)
 | 
						|
		{
 | 
						|
			is16bits = 1;
 | 
						|
			mode[chn] |= 0x04;	/* 16 bit data */
 | 
						|
		}
 | 
						|
		else
 | 
						|
			is16bits = 0;
 | 
						|
 | 
						|
		dram_loc = this_one * pcm_bsize;
 | 
						|
		dram_loc += chn * pcm_banksize;
 | 
						|
 | 
						|
		if (this_one == (pcm_nblk - 1))	/* Last fragment of the DRAM buffer */
 | 
						|
		{
 | 
						|
			mode[chn] |= 0x08;	/* Enable loop */
 | 
						|
			ramp_mode[chn] = 0x03;	/* Disable rollover bit */
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (chn == 0)
 | 
						|
				ramp_mode[chn] = 0x04;	/* Enable rollover bit */
 | 
						|
		}
 | 
						|
		spin_lock_irqsave(&gus_lock,flags);
 | 
						|
		gus_select_voice(chn);
 | 
						|
		gus_voice_freq(speed);
 | 
						|
 | 
						|
		if (gus_audio_channels == 1)
 | 
						|
			gus_voice_balance(7);		/* mono */
 | 
						|
		else if (chn == 0)
 | 
						|
			gus_voice_balance(0);		/* left */
 | 
						|
		else
 | 
						|
			gus_voice_balance(15);		/* right */
 | 
						|
 | 
						|
		if (!pcm_active)	/* Playback not already active */
 | 
						|
		{
 | 
						|
			/*
 | 
						|
			 * 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.
 | 
						|
			 */
 | 
						|
 | 
						|
			gus_voice_off();
 | 
						|
			gus_rampoff();
 | 
						|
			gus_voice_volume(1530 + (25 * gus_pcm_volume));
 | 
						|
			gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
 | 
						|
 | 
						|
			gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits);	/* Starting position */
 | 
						|
			gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits);	/* Loop start */
 | 
						|
 | 
						|
			if (chn != 0)
 | 
						|
				gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
 | 
						|
						   0, is16bits);	/* Loop end location */
 | 
						|
		}
 | 
						|
		if (chn == 0)
 | 
						|
			gus_write_addr(0x04, dram_loc + pcm_bsize - 1,
 | 
						|
					 0, is16bits);	/* Loop end location */
 | 
						|
		else
 | 
						|
			mode[chn] |= 0x08;	/* Enable looping */
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
	}
 | 
						|
	for (chn = 0; chn < gus_audio_channels; chn++)
 | 
						|
	{
 | 
						|
		spin_lock_irqsave(&gus_lock,flags);
 | 
						|
		gus_select_voice(chn);
 | 
						|
		gus_write8(0x0d, ramp_mode[chn]);
 | 
						|
		if (iw_mode)
 | 
						|
			gus_write8(0x15, 0x00);	/* Reset voice deactivate bit of SMSI */
 | 
						|
		gus_voice_on(mode[chn]);
 | 
						|
		spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
	}
 | 
						|
	pcm_active = 1;
 | 
						|
}
 | 
						|
 | 
						|
static void gus_transfer_output_block(int dev, unsigned long buf,
 | 
						|
			  int total_count, int intrflag, int chn)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	 * 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.
 | 
						|
	 *
 | 
						|
	 * 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;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
 | 
						|
	count = total_count / gus_audio_channels;
 | 
						|
 | 
						|
	if (chn == 0)
 | 
						|
	{
 | 
						|
		if (pcm_qlen >= pcm_nblk)
 | 
						|
			printk(KERN_WARNING "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;
 | 
						|
 | 
						|
	gus_write8(0x41, 0);	/* Disable GF1 DMA */
 | 
						|
	DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE);
 | 
						|
 | 
						|
	address = this_one * pcm_bsize;
 | 
						|
	address += chn * pcm_banksize;
 | 
						|
 | 
						|
	if (audio_devs[dev]->dmap_out->dma > 3)
 | 
						|
	{
 | 
						|
		hold_address = address;
 | 
						|
		address = address >> 1;
 | 
						|
		address &= 0x0001ffffL;
 | 
						|
		address |= (hold_address & 0x000c0000L);
 | 
						|
	}
 | 
						|
	gus_write16(0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
 | 
						|
 | 
						|
	dma_command = 0x21;	/* IRQ enable, DMA start */
 | 
						|
 | 
						|
	if (gus_audio_bits != 8)
 | 
						|
		dma_command |= 0x40;	/* 16 bit _DATA_ */
 | 
						|
	else
 | 
						|
		dma_command |= 0x80;	/* Invert MSB */
 | 
						|
 | 
						|
	if (audio_devs[dev]->dmap_out->dma > 3)
 | 
						|
		dma_command |= 0x04;	/* 16 bit DMA channel */
 | 
						|
 | 
						|
	gus_write8(0x41, dma_command);	/* Kick start */
 | 
						|
 | 
						|
	if (chn == (gus_audio_channels - 1))	/* Last channel */
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 * Last (right or mono) channel data
 | 
						|
		 */
 | 
						|
		dma_active = 1;	/* DMA started. There is a unacknowledged buffer */
 | 
						|
		active_device = GUS_DEV_PCM_DONE;
 | 
						|
		if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize))
 | 
						|
		{
 | 
						|
			play_next_pcm_block();
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 * Left channel data. The right channel
 | 
						|
		 * is transferred after DMA interrupt
 | 
						|
		 */
 | 
						|
		active_device = GUS_DEV_PCM_CONTINUE;
 | 
						|
	}
 | 
						|
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_uninterleave8(char *buf, int l)
 | 
						|
{
 | 
						|
/* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */
 | 
						|
	int i, p = 0, halfsize = l / 2;
 | 
						|
	char *buf2 = buf + halfsize, *src = bounce_buf;
 | 
						|
 | 
						|
	memcpy(bounce_buf, buf, l);
 | 
						|
 | 
						|
	for (i = 0; i < halfsize; i++)
 | 
						|
	{
 | 
						|
		buf[i] = src[p++];	/* Left channel */
 | 
						|
		buf2[i] = src[p++];	/* Right channel */
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void gus_uninterleave16(short *buf, int l)
 | 
						|
{
 | 
						|
/* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */
 | 
						|
	int i, p = 0, halfsize = l / 2;
 | 
						|
	short *buf2 = buf + halfsize, *src = (short *) bounce_buf;
 | 
						|
 | 
						|
	memcpy(bounce_buf, (char *) buf, l * 2);
 | 
						|
 | 
						|
	for (i = 0; i < halfsize; i++)
 | 
						|
	{
 | 
						|
		buf[i] = src[p++];	/* Left channel */
 | 
						|
		buf2[i] = src[p++];	/* Right channel */
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void gus_audio_output_block(int dev, unsigned long buf, int total_count,
 | 
						|
		       int intrflag)
 | 
						|
{
 | 
						|
	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 | 
						|
 | 
						|
	dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT;
 | 
						|
 | 
						|
	pcm_current_buf = buf;
 | 
						|
	pcm_current_count = total_count;
 | 
						|
	pcm_current_intrflag = intrflag;
 | 
						|
	pcm_current_dev = dev;
 | 
						|
	if (gus_audio_channels == 2)
 | 
						|
	{
 | 
						|
		char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys);
 | 
						|
 | 
						|
		if (gus_audio_bits == 8)
 | 
						|
			gus_uninterleave8(b, total_count);
 | 
						|
		else
 | 
						|
			gus_uninterleave16((short *) b, total_count / 2);
 | 
						|
	}
 | 
						|
	gus_transfer_output_block(dev, buf, total_count, intrflag, 0);
 | 
						|
}
 | 
						|
 | 
						|
static void gus_audio_start_input(int dev, unsigned long buf, int count,
 | 
						|
		      int intrflag)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	unsigned char mode;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
 | 
						|
	DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ);
 | 
						|
	mode = 0xa0;		/* DMA IRQ enabled, invert MSB */
 | 
						|
 | 
						|
	if (audio_devs[dev]->dmap_in->dma > 3)
 | 
						|
		mode |= 0x04;	/* 16 bit DMA channel */
 | 
						|
	if (gus_audio_channels > 1)
 | 
						|
		mode |= 0x02;	/* Stereo */
 | 
						|
	mode |= 0x01;		/* DMA enable */
 | 
						|
 | 
						|
	gus_write8(0x49, mode);
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
static int gus_audio_prepare_for_input(int dev, int bsize, int bcount)
 | 
						|
{
 | 
						|
	unsigned int rate;
 | 
						|
 | 
						|
	gus_audio_bsize = bsize;
 | 
						|
	audio_devs[dev]->dmap_in->flags |= DMA_NODMA;
 | 
						|
	rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
 | 
						|
 | 
						|
	gus_write8(0x48, rate & 0xff);	/* Set sampling rate */
 | 
						|
 | 
						|
	if (gus_audio_bits != 8)
 | 
						|
	{
 | 
						|
/*		printk("GUS Error: 16 bit recording not supported\n");*/
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int gus_audio_prepare_for_output(int dev, int bsize, int bcount)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	long mem_ptr, mem_size;
 | 
						|
 | 
						|
	audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT;
 | 
						|
	mem_ptr = 0;
 | 
						|
	mem_size = gus_mem_size / gus_audio_channels;
 | 
						|
 | 
						|
	if (mem_size > (256 * 1024))
 | 
						|
		mem_size = 256 * 1024;
 | 
						|
 | 
						|
	pcm_bsize = bsize / gus_audio_channels;
 | 
						|
	pcm_head = pcm_tail = pcm_qlen = 0;
 | 
						|
 | 
						|
	pcm_nblk = 2;		/* 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_audio_bits != 8 && pcm_banksize == (256 * 1024))
 | 
						|
		pcm_nblk--;
 | 
						|
	gus_write8(0x41, 0);	/* Disable GF1 DMA */
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int gus_local_qlen(int dev)
 | 
						|
{
 | 
						|
	return pcm_qlen;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static struct audio_driver gus_audio_driver =
 | 
						|
{
 | 
						|
	.owner			= THIS_MODULE,
 | 
						|
	.open			= gus_audio_open,
 | 
						|
	.close			= gus_audio_close,
 | 
						|
	.output_block		= gus_audio_output_block,
 | 
						|
	.start_input		= gus_audio_start_input,
 | 
						|
	.ioctl			= gus_audio_ioctl,
 | 
						|
	.prepare_for_input	= gus_audio_prepare_for_input,
 | 
						|
	.prepare_for_output	= gus_audio_prepare_for_output,
 | 
						|
	.halt_io		= gus_audio_reset,
 | 
						|
	.local_qlen		= gus_local_qlen,
 | 
						|
};
 | 
						|
 | 
						|
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) / (unsigned) 128;
 | 
						|
	voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128;
 | 
						|
	voices[voice].bender = 0;
 | 
						|
	voices[voice].bender_range = info->bender_range;
 | 
						|
 | 
						|
	if (chn == 9)
 | 
						|
		voices[voice].fixed_pitch = 1;
 | 
						|
}
 | 
						|
 | 
						|
static void guswave_bender(int dev, int voice, int value)
 | 
						|
{
 | 
						|
	int freq;
 | 
						|
	unsigned long   flags;
 | 
						|
 | 
						|
	voices[voice].bender = value - 8192;
 | 
						|
	freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0);
 | 
						|
	voices[voice].current_freq = freq;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	gus_select_voice(voice);
 | 
						|
	gus_voice_freq(freq);
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
 | 
						|
{
 | 
						|
	int i, p, best = -1, best_time = 0x7fffffff;
 | 
						|
 | 
						|
	p = alloc->ptr;
 | 
						|
	/*
 | 
						|
	 * First look for a completely stopped voice
 | 
						|
	 */
 | 
						|
 | 
						|
	for (i = 0; i < alloc->max_voice; i++)
 | 
						|
	{
 | 
						|
		if (alloc->map[p] == 0)
 | 
						|
		{
 | 
						|
			alloc->ptr = p;
 | 
						|
			return p;
 | 
						|
		}
 | 
						|
		if (alloc->alloc_times[p] < best_time)
 | 
						|
		{
 | 
						|
			best = p;
 | 
						|
			best_time = alloc->alloc_times[p];
 | 
						|
		}
 | 
						|
		p = (p + 1) % alloc->max_voice;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Then look for a releasing voice
 | 
						|
	 */
 | 
						|
 | 
						|
	for (i = 0; i < alloc->max_voice; i++)
 | 
						|
	{
 | 
						|
		if (alloc->map[p] == 0xffff)
 | 
						|
		{
 | 
						|
			alloc->ptr = p;
 | 
						|
			return p;
 | 
						|
		}
 | 
						|
		p = (p + 1) % alloc->max_voice;
 | 
						|
	}
 | 
						|
	if (best >= 0)
 | 
						|
		p = best;
 | 
						|
 | 
						|
	alloc->ptr = p;
 | 
						|
	return p;
 | 
						|
}
 | 
						|
 | 
						|
static struct synth_operations guswave_operations =
 | 
						|
{
 | 
						|
	.owner		= THIS_MODULE,
 | 
						|
	.id		= "GUS",
 | 
						|
	.info		= &gus_info,
 | 
						|
	.midi_dev	= 0,
 | 
						|
	.synth_type	= SYNTH_TYPE_SAMPLE,
 | 
						|
	.synth_subtype	= SAMPLE_TYPE_GUS,
 | 
						|
	.open		= guswave_open,
 | 
						|
	.close		= guswave_close,
 | 
						|
	.ioctl		= guswave_ioctl,
 | 
						|
	.kill_note	= guswave_kill_note,
 | 
						|
	.start_note	= guswave_start_note,
 | 
						|
	.set_instr	= guswave_set_instr,
 | 
						|
	.reset		= guswave_reset,
 | 
						|
	.hw_control	= guswave_hw_control,
 | 
						|
	.load_patch	= guswave_load_patch,
 | 
						|
	.aftertouch	= guswave_aftertouch,
 | 
						|
	.controller	= guswave_controller,
 | 
						|
	.panning	= guswave_panning,
 | 
						|
	.volume_method	= guswave_volume_method,
 | 
						|
	.bender		= guswave_bender,
 | 
						|
	.alloc_voice	= guswave_alloc,
 | 
						|
	.setup_voice	= guswave_setup_voice
 | 
						|
};
 | 
						|
 | 
						|
static void set_input_volumes(void)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	unsigned char mask = 0xff & ~0x06;	/* Just line out enabled */
 | 
						|
 | 
						|
	if (have_gus_max)	/* Don't disturb GUS MAX */
 | 
						|
		return;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
 | 
						|
	/*
 | 
						|
	 *    Enable channels having vol > 10%
 | 
						|
	 *      Note! bit 0x01 means the line in DISABLED while 0x04 means
 | 
						|
	 *            the mic in ENABLED.
 | 
						|
	 */
 | 
						|
	if (gus_line_vol > 10)
 | 
						|
		mask &= ~0x01;
 | 
						|
	if (gus_mic_vol > 10)
 | 
						|
		mask |= 0x04;
 | 
						|
 | 
						|
	if (recording_active)
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 *    Disable channel, if not selected for recording
 | 
						|
		 */
 | 
						|
		if (!(gus_recmask & SOUND_MASK_LINE))
 | 
						|
			mask |= 0x01;
 | 
						|
		if (!(gus_recmask & SOUND_MASK_MIC))
 | 
						|
			mask &= ~0x04;
 | 
						|
	}
 | 
						|
	mix_image &= ~0x07;
 | 
						|
	mix_image |= mask & 0x07;
 | 
						|
	outb((mix_image), u_Mixer);
 | 
						|
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
}
 | 
						|
 | 
						|
#define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
 | 
						|
			 SOUND_MASK_SYNTH|SOUND_MASK_PCM)
 | 
						|
 | 
						|
int gus_default_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
 | 
						|
{
 | 
						|
	int vol, val;
 | 
						|
 | 
						|
	if (((cmd >> 8) & 0xff) != 'M')
 | 
						|
		return -EINVAL;
 | 
						|
 | 
						|
	if (!access_ok(VERIFY_WRITE, arg, sizeof(int)))
 | 
						|
		return -EFAULT;
 | 
						|
 | 
						|
	if (_SIOC_DIR(cmd) & _SIOC_WRITE) 
 | 
						|
	{
 | 
						|
		if (__get_user(val, (int __user *) arg))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		switch (cmd & 0xff) 
 | 
						|
		{
 | 
						|
			case SOUND_MIXER_RECSRC:
 | 
						|
				gus_recmask = val & MIX_DEVS;
 | 
						|
				if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
 | 
						|
					gus_recmask = SOUND_MASK_MIC;
 | 
						|
				/* Note! Input volumes are updated during next open for recording */
 | 
						|
				val = gus_recmask;
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_MIC:
 | 
						|
				vol = val & 0xff;
 | 
						|
				if (vol < 0)
 | 
						|
					vol = 0;
 | 
						|
				if (vol > 100)
 | 
						|
					vol = 100;
 | 
						|
				gus_mic_vol = vol;
 | 
						|
				set_input_volumes();
 | 
						|
				val = vol | (vol << 8);
 | 
						|
				break;
 | 
						|
				
 | 
						|
			case SOUND_MIXER_LINE:
 | 
						|
				vol = val & 0xff;
 | 
						|
				if (vol < 0)
 | 
						|
					vol = 0;
 | 
						|
				if (vol > 100)
 | 
						|
					vol = 100;
 | 
						|
				gus_line_vol = vol;
 | 
						|
				set_input_volumes();
 | 
						|
				val = vol | (vol << 8);
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_PCM:
 | 
						|
				gus_pcm_volume = val & 0xff;
 | 
						|
				if (gus_pcm_volume < 0)
 | 
						|
					gus_pcm_volume = 0;
 | 
						|
				if (gus_pcm_volume > 100)
 | 
						|
					gus_pcm_volume = 100;
 | 
						|
				gus_audio_update_volume();
 | 
						|
				val = gus_pcm_volume | (gus_pcm_volume << 8);
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_SYNTH:
 | 
						|
				gus_wave_volume = val & 0xff;
 | 
						|
				if (gus_wave_volume < 0)
 | 
						|
					gus_wave_volume = 0;
 | 
						|
				if (gus_wave_volume > 100)
 | 
						|
					gus_wave_volume = 100;
 | 
						|
				if (active_device == GUS_DEV_WAVE) 
 | 
						|
				{
 | 
						|
					int voice;
 | 
						|
					for (voice = 0; voice < nr_voices; voice++)
 | 
						|
					dynamic_volume_change(voice);	/* Apply the new vol */
 | 
						|
				}
 | 
						|
				val = gus_wave_volume | (gus_wave_volume << 8);
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				return -EINVAL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		switch (cmd & 0xff) 
 | 
						|
		{
 | 
						|
			/*
 | 
						|
			 * Return parameters
 | 
						|
			 */
 | 
						|
			case SOUND_MIXER_RECSRC:
 | 
						|
				val = gus_recmask;
 | 
						|
				break;
 | 
						|
					
 | 
						|
			case SOUND_MIXER_DEVMASK:
 | 
						|
				val = MIX_DEVS;
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_STEREODEVS:
 | 
						|
				val = 0;
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_RECMASK:
 | 
						|
				val = SOUND_MASK_MIC | SOUND_MASK_LINE;
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_CAPS:
 | 
						|
				val = 0;
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_MIC:
 | 
						|
				val = gus_mic_vol | (gus_mic_vol << 8);
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_LINE:
 | 
						|
				val = gus_line_vol | (gus_line_vol << 8);
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_PCM:
 | 
						|
				val = gus_pcm_volume | (gus_pcm_volume << 8);
 | 
						|
				break;
 | 
						|
 | 
						|
			case SOUND_MIXER_SYNTH:
 | 
						|
				val = gus_wave_volume | (gus_wave_volume << 8);
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				return -EINVAL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return __put_user(val, (int __user *)arg);
 | 
						|
}
 | 
						|
 | 
						|
static struct mixer_operations gus_mixer_operations =
 | 
						|
{
 | 
						|
	.owner	= THIS_MODULE,
 | 
						|
	.id	= "GUS",
 | 
						|
	.name	= "Gravis Ultrasound",
 | 
						|
	.ioctl	= gus_default_mixer_ioctl
 | 
						|
};
 | 
						|
 | 
						|
static int __init gus_default_mixer_init(void)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
 | 
						|
	if ((n = sound_alloc_mixerdev()) != -1)
 | 
						|
	{	
 | 
						|
		/*
 | 
						|
		 * Don't install if there is another
 | 
						|
		 * mixer
 | 
						|
		 */
 | 
						|
		mixer_devs[n] = &gus_mixer_operations;
 | 
						|
	}
 | 
						|
	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 */
 | 
						|
		outb((mix_image), u_Mixer);
 | 
						|
	}
 | 
						|
	return n;
 | 
						|
}
 | 
						|
 | 
						|
void __init gus_wave_init(struct address_info *hw_config)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	unsigned char val;
 | 
						|
	char *model_num = "2.4";
 | 
						|
	char tmp[64];
 | 
						|
	int gus_type = 0x24;	/* 2.4 */
 | 
						|
 | 
						|
	int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
 | 
						|
	int sdev;
 | 
						|
 | 
						|
	hw_config->slots[0] = -1;	/* No wave */
 | 
						|
	hw_config->slots[1] = -1;	/* No ad1848 */
 | 
						|
	hw_config->slots[4] = -1;	/* No audio */
 | 
						|
	hw_config->slots[5] = -1;	/* No mixer */
 | 
						|
 | 
						|
	if (!gus_pnp_flag)
 | 
						|
	{
 | 
						|
		if (irq < 0 || irq > 15)
 | 
						|
		{
 | 
						|
			printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (dma < 0 || dma > 7 || dma == 4)
 | 
						|
	{
 | 
						|
		printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	gus_irq = irq;
 | 
						|
	gus_dma = dma;
 | 
						|
	gus_dma2 = dma2;
 | 
						|
	gus_hw_config = hw_config;
 | 
						|
 | 
						|
	if (gus_dma2 == -1)
 | 
						|
		gus_dma2 = dma;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Try to identify the GUS model.
 | 
						|
	 *
 | 
						|
	 *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
 | 
						|
	 */
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
	outb((0x20), gus_base + 0x0f);
 | 
						|
	val = inb(gus_base + 0x0f);
 | 
						|
	spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
 | 
						|
	if (gus_pnp_flag || (val != 0xff && (val & 0x06)))	/* Should be 0x02?? */
 | 
						|
	{
 | 
						|
		int             ad_flags = 0;
 | 
						|
 | 
						|
		if (gus_pnp_flag)
 | 
						|
			ad_flags = 0x12345678;	/* Interwave "magic" */
 | 
						|
		/*
 | 
						|
		 * It has the digital ASIC so the card is at least v3.4.
 | 
						|
		 * Next try to detect the true model.
 | 
						|
		 */
 | 
						|
 | 
						|
		if (gus_pnp_flag)	/* Hack hack hack */
 | 
						|
			val = 10;
 | 
						|
		else
 | 
						|
			val = inb(u_MixSelect);
 | 
						|
 | 
						|
		/*
 | 
						|
		 * 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.
 | 
						|
		 *
 | 
						|
		 */
 | 
						|
 | 
						|
		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;
 | 
						|
			request_region(u_MixSelect, 1, "GUS mixer");
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			struct resource *ports;
 | 
						|
			ports = request_region(gus_base + 0x10c, 4, "ad1848");
 | 
						|
			model_num = "MAX";
 | 
						|
			gus_type = 0x40;
 | 
						|
			mixer_type = CS4231;
 | 
						|
#ifdef CONFIG_SOUND_GUSMAX
 | 
						|
			{
 | 
						|
				unsigned char   max_config = 0x40;	/* Codec enable */
 | 
						|
 | 
						|
				if (gus_dma2 == -1)
 | 
						|
					gus_dma2 = gus_dma;
 | 
						|
 | 
						|
				if (gus_dma > 3)
 | 
						|
					max_config |= 0x10;		/* 16 bit capture DMA */
 | 
						|
 | 
						|
				if (gus_dma2 > 3)
 | 
						|
					max_config |= 0x20;		/* 16 bit playback DMA */
 | 
						|
 | 
						|
				max_config |= (gus_base >> 4) & 0x0f;	/* Extract the X from 2X0 */
 | 
						|
 | 
						|
				outb((max_config), gus_base + 0x106);	/* UltraMax control */
 | 
						|
			}
 | 
						|
 | 
						|
			if (!ports)
 | 
						|
				goto no_cs4231;
 | 
						|
 | 
						|
			if (ad1848_detect(ports, &ad_flags, hw_config->osp))
 | 
						|
			{
 | 
						|
				char           *name = "GUS MAX";
 | 
						|
				int             old_num_mixers = num_mixers;
 | 
						|
 | 
						|
				if (gus_pnp_flag)
 | 
						|
					name = "GUS PnP";
 | 
						|
 | 
						|
				gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
 | 
						|
				gus_wave_volume = 90;
 | 
						|
				have_gus_max = 1;
 | 
						|
				if (hw_config->name)
 | 
						|
					name = hw_config->name;
 | 
						|
 | 
						|
				hw_config->slots[1] = ad1848_init(name, ports,
 | 
						|
							-irq, gus_dma2,	/* Playback DMA */
 | 
						|
							gus_dma,	/* Capture DMA */
 | 
						|
							1,		/* Share DMA channels with GF1 */
 | 
						|
							hw_config->osp,
 | 
						|
							THIS_MODULE);
 | 
						|
 | 
						|
				if (num_mixers > old_num_mixers)
 | 
						|
				{
 | 
						|
					/* GUS has it's own mixer map */
 | 
						|
					AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
 | 
						|
					AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
 | 
						|
					AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				release_region(gus_base + 0x10c, 4);
 | 
						|
			no_cs4231:
 | 
						|
				printk(KERN_WARNING "GUS: No CS4231 ??");
 | 
						|
			}
 | 
						|
#else
 | 
						|
			printk(KERN_ERR "GUS MAX found, but not compiled in\n");
 | 
						|
#endif
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 * ASIC not detected so the card must be 2.2 or 2.4.
 | 
						|
		 * There could still be the 16-bit/mixer daughter card.
 | 
						|
		 */
 | 
						|
	}
 | 
						|
 | 
						|
	if (hw_config->name)
 | 
						|
		snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name,
 | 
						|
			 (int) gus_mem_size / 1024);
 | 
						|
	else if (gus_pnp_flag)
 | 
						|
		snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)",
 | 
						|
			 (int) gus_mem_size / 1024);
 | 
						|
	else
 | 
						|
		snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num,
 | 
						|
			 (int) gus_mem_size / 1024);
 | 
						|
 | 
						|
 | 
						|
	samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples));
 | 
						|
	if (samples == NULL)
 | 
						|
	{
 | 
						|
		printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	conf_printf(tmp, hw_config);
 | 
						|
	strlcpy(gus_info.name, tmp, sizeof(gus_info.name));
 | 
						|
 | 
						|
	if ((sdev = sound_alloc_synthdev()) == -1)
 | 
						|
		printk(KERN_WARNING "gus_init: Too many synthesizers\n");
 | 
						|
	else
 | 
						|
	{
 | 
						|
		voice_alloc = &guswave_operations.alloc;
 | 
						|
		if (iw_mode)
 | 
						|
			guswave_operations.id = "IWAVE";
 | 
						|
		hw_config->slots[0] = sdev;
 | 
						|
		synth_devs[sdev] = &guswave_operations;
 | 
						|
		sequencer_init();
 | 
						|
		gus_tmr_install(gus_base + 8);
 | 
						|
	}
 | 
						|
 | 
						|
	reset_sample_memory();
 | 
						|
 | 
						|
	gus_initialize();
 | 
						|
	
 | 
						|
	if ((gus_mem_size > 0) && !gus_no_wave_dma)
 | 
						|
	{
 | 
						|
		hw_config->slots[4] = -1;
 | 
						|
		if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
 | 
						|
					"Ultrasound",
 | 
						|
					&gus_audio_driver,
 | 
						|
					sizeof(struct audio_driver),
 | 
						|
					NEEDS_RESTART |
 | 
						|
		                   	((!iw_mode && dma2 != dma && dma2 != -1) ?
 | 
						|
						DMA_DUPLEX : 0),
 | 
						|
					AFMT_U8 | AFMT_S16_LE,
 | 
						|
					NULL, dma, dma2)) < 0)
 | 
						|
		{
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		hw_config->slots[4] = gus_devnum;
 | 
						|
		audio_devs[gus_devnum]->min_fragment = 9;	/* 512k */
 | 
						|
		audio_devs[gus_devnum]->max_fragment = 11;	/* 8k (must match size of bounce_buf */
 | 
						|
		audio_devs[gus_devnum]->mixer_dev = -1;	/* Next mixer# */
 | 
						|
		audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
 | 
						|
	}
 | 
						|
	
 | 
						|
	/*
 | 
						|
	 *  Mixer dependent initialization.
 | 
						|
	 */
 | 
						|
 | 
						|
	switch (mixer_type)
 | 
						|
	{
 | 
						|
		case ICS2101:
 | 
						|
			gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
 | 
						|
			gus_wave_volume = 90;
 | 
						|
			request_region(u_MixSelect, 1, "GUS mixer");
 | 
						|
			hw_config->slots[5] = ics2101_mixer_init();
 | 
						|
			audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];	/* Next mixer# */
 | 
						|
			return;
 | 
						|
 | 
						|
		case CS4231:
 | 
						|
			/* Initialized elsewhere (ad1848.c) */
 | 
						|
		default:
 | 
						|
			hw_config->slots[5] = gus_default_mixer_init();
 | 
						|
			audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];	/* Next mixer# */
 | 
						|
			return;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void __exit gus_wave_unload(struct address_info *hw_config)
 | 
						|
{
 | 
						|
#ifdef CONFIG_SOUND_GUSMAX
 | 
						|
	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);
 | 
						|
	}
 | 
						|
	if (hw_config->slots[0] != -1)
 | 
						|
		sound_unload_synthdev(hw_config->slots[0]);
 | 
						|
	if (hw_config->slots[1] != -1)
 | 
						|
		sound_unload_audiodev(hw_config->slots[1]);
 | 
						|
	if (hw_config->slots[2] != -1)
 | 
						|
		sound_unload_mididev(hw_config->slots[2]);
 | 
						|
	if (hw_config->slots[4] != -1)
 | 
						|
		sound_unload_audiodev(hw_config->slots[4]);
 | 
						|
	if (hw_config->slots[5] != -1)
 | 
						|
		sound_unload_mixerdev(hw_config->slots[5]);
 | 
						|
	
 | 
						|
	vfree(samples);
 | 
						|
	samples=NULL;
 | 
						|
}
 | 
						|
/* called in interrupt context */
 | 
						|
static void do_loop_irq(int voice)
 | 
						|
{
 | 
						|
	unsigned char   tmp;
 | 
						|
	int             mode, parm;
 | 
						|
 | 
						|
	spin_lock(&gus_lock);
 | 
						|
	gus_select_voice(voice);
 | 
						|
 | 
						|
	tmp = gus_read8(0x00);
 | 
						|
	tmp &= ~0x20;		/*
 | 
						|
				 * Disable wave IRQ for this_one voice
 | 
						|
				 */
 | 
						|
	gus_write8(0x00, tmp);
 | 
						|
 | 
						|
	if (tmp & 0x03)		/* Voice stopped */
 | 
						|
		voice_alloc->map[voice] = 0;
 | 
						|
 | 
						|
	mode = voices[voice].loop_irq_mode;
 | 
						|
	voices[voice].loop_irq_mode = 0;
 | 
						|
	parm = voices[voice].loop_irq_parm;
 | 
						|
 | 
						|
	switch (mode)
 | 
						|
	{
 | 
						|
		case LMODE_FINISH:	/*
 | 
						|
					 * Final loop finished, shoot volume down
 | 
						|
					 */
 | 
						|
 | 
						|
			if ((int) (gus_read16(0x09) >> 4) < 100)	/*
 | 
						|
									 * Get current volume
 | 
						|
									 */
 | 
						|
			{
 | 
						|
				gus_voice_off();
 | 
						|
				gus_rampoff();
 | 
						|
				gus_voice_init(voice);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			gus_ramp_range(65, 4065);
 | 
						|
			gus_ramp_rate(0, 63);		/*
 | 
						|
							 * Fastest possible rate
 | 
						|
							 */
 | 
						|
			gus_rampon(0x20 | 0x40);	/*
 | 
						|
							 * Ramp down, once, irq
 | 
						|
							 */
 | 
						|
			voices[voice].volume_irq_mode = VMODE_HALT;
 | 
						|
			break;
 | 
						|
 | 
						|
		case LMODE_PCM_STOP:
 | 
						|
			pcm_active = 0;	/* Signal to the play_next_pcm_block routine */
 | 
						|
		case LMODE_PCM:
 | 
						|
		{
 | 
						|
			pcm_qlen--;
 | 
						|
			pcm_head = (pcm_head + 1) % pcm_nblk;
 | 
						|
			if (pcm_qlen && pcm_active)
 | 
						|
			{
 | 
						|
				play_next_pcm_block();
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* Underrun. Just stop the voice */
 | 
						|
				gus_select_voice(0);	/* Left channel */
 | 
						|
				gus_voice_off();
 | 
						|
				gus_rampoff();
 | 
						|
				gus_select_voice(1);	/* Right channel */
 | 
						|
				gus_voice_off();
 | 
						|
				gus_rampoff();
 | 
						|
				pcm_active = 0;
 | 
						|
			}
 | 
						|
 | 
						|
			/*
 | 
						|
			 * If the queue was full before this interrupt, the DMA transfer was
 | 
						|
			 * suspended. Let it continue now.
 | 
						|
			 */
 | 
						|
			
 | 
						|
			if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
 | 
						|
				DMAbuf_outputintr(gus_devnum, 0);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	spin_unlock(&gus_lock);
 | 
						|
}
 | 
						|
 | 
						|
static void do_volume_irq(int voice)
 | 
						|
{
 | 
						|
	unsigned char tmp;
 | 
						|
	int mode, parm;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	spin_lock_irqsave(&gus_lock,flags);
 | 
						|
 | 
						|
	gus_select_voice(voice);
 | 
						|
	tmp = gus_read8(0x0d);
 | 
						|
	tmp &= ~0x20;		/*
 | 
						|
				 * Disable volume ramp IRQ
 | 
						|
				 */
 | 
						|
	gus_write8(0x0d, tmp);
 | 
						|
 | 
						|
	mode = voices[voice].volume_irq_mode;
 | 
						|
	voices[voice].volume_irq_mode = 0;
 | 
						|
	parm = voices[voice].volume_irq_parm;
 | 
						|
 | 
						|
	switch (mode)
 | 
						|
	{
 | 
						|
		case VMODE_HALT:	/* Decay phase finished */
 | 
						|
			if (iw_mode)
 | 
						|
				gus_write8(0x15, 0x02);	/* Set voice deactivate bit of SMSI */
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			gus_voice_init(voice);
 | 
						|
			break;
 | 
						|
 | 
						|
		case VMODE_ENVELOPE:
 | 
						|
			gus_rampoff();
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			step_envelope(voice);
 | 
						|
			break;
 | 
						|
 | 
						|
		case VMODE_START_NOTE:
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
			guswave_start_note2(voices[voice].dev_pending, voice,
 | 
						|
				      voices[voice].note_pending, voices[voice].volume_pending);
 | 
						|
			if (voices[voice].kill_pending)
 | 
						|
				guswave_kill_note(voices[voice].dev_pending, voice,
 | 
						|
					  voices[voice].note_pending, 0);
 | 
						|
 | 
						|
			if (voices[voice].sample_pending >= 0)
 | 
						|
			{
 | 
						|
				guswave_set_instr(voices[voice].dev_pending, voice,
 | 
						|
					voices[voice].sample_pending);
 | 
						|
				voices[voice].sample_pending = -1;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			spin_unlock_irqrestore(&gus_lock,flags);
 | 
						|
	}
 | 
						|
}
 | 
						|
/* called in irq context */
 | 
						|
void gus_voice_irq(void)
 | 
						|
{
 | 
						|
	unsigned long wave_ignore = 0, volume_ignore = 0;
 | 
						|
	unsigned long voice_bit;
 | 
						|
 | 
						|
	unsigned char src, voice;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		src = gus_read8(0x0f);	/*
 | 
						|
					 * Get source info
 | 
						|
					 */
 | 
						|
		voice = src & 0x1f;
 | 
						|
		src &= 0xc0;
 | 
						|
 | 
						|
		if (src == (0x80 | 0x40))
 | 
						|
			return;	/*
 | 
						|
				 * No interrupt
 | 
						|
				 */
 | 
						|
 | 
						|
		voice_bit = 1 << voice;
 | 
						|
 | 
						|
		if (!(src & 0x80))	/*
 | 
						|
					 * Wave IRQ pending
 | 
						|
					 */
 | 
						|
			if (!(wave_ignore & voice_bit) && (int) voice < nr_voices)	/*
 | 
						|
											 * Not done
 | 
						|
											 * yet
 | 
						|
											 */
 | 
						|
			{
 | 
						|
				wave_ignore |= voice_bit;
 | 
						|
				do_loop_irq(voice);
 | 
						|
			}
 | 
						|
		if (!(src & 0x40))	/*
 | 
						|
					 * Volume IRQ pending
 | 
						|
					 */
 | 
						|
			if (!(volume_ignore & voice_bit) && (int) voice < nr_voices)	/*
 | 
						|
											   * Not done
 | 
						|
											   * yet
 | 
						|
											 */
 | 
						|
			{
 | 
						|
				volume_ignore |= voice_bit;
 | 
						|
				do_volume_irq(voice);
 | 
						|
			}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void guswave_dma_irq(void)
 | 
						|
{
 | 
						|
	unsigned char   status;
 | 
						|
 | 
						|
	status = gus_look8(0x41);	/* Get DMA IRQ Status */
 | 
						|
	if (status & 0x40)	/* DMA interrupt pending */
 | 
						|
		switch (active_device)
 | 
						|
		{
 | 
						|
			case GUS_DEV_WAVE:
 | 
						|
				wake_up(&dram_sleeper);
 | 
						|
				break;
 | 
						|
 | 
						|
			case GUS_DEV_PCM_CONTINUE:	/* Left channel data transferred */
 | 
						|
				gus_write8(0x41, 0);	/* Disable GF1 DMA */
 | 
						|
				gus_transfer_output_block(pcm_current_dev, pcm_current_buf,
 | 
						|
						pcm_current_count,
 | 
						|
						pcm_current_intrflag, 1);
 | 
						|
				break;
 | 
						|
 | 
						|
			case GUS_DEV_PCM_DONE:	/* Right or mono channel data transferred */
 | 
						|
				gus_write8(0x41, 0);	/* Disable GF1 DMA */
 | 
						|
				if (pcm_qlen < pcm_nblk)
 | 
						|
				{
 | 
						|
					dma_active = 0;
 | 
						|
					if (gus_busy)
 | 
						|
					{
 | 
						|
						if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
 | 
						|
							DMAbuf_outputintr(gus_devnum, 0);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				break;
 | 
						|
	}
 | 
						|
	status = gus_look8(0x49);	/*
 | 
						|
					 * Get Sampling IRQ Status
 | 
						|
					 */
 | 
						|
	if (status & 0x40)	/*
 | 
						|
				 * Sampling Irq pending
 | 
						|
				 */
 | 
						|
	{
 | 
						|
		DMAbuf_inputintr(gus_devnum);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Timer stuff
 | 
						|
 */
 | 
						|
 | 
						|
static volatile int select_addr, data_addr;
 | 
						|
static volatile int curr_timer;
 | 
						|
 | 
						|
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 */
 | 
						|
	}
 | 
						|
 | 
						|
	gus_timer_enabled = 1;
 | 
						|
}
 | 
						|
 | 
						|
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 */
 | 
						|
	gus_timer_enabled = 1;
 | 
						|
}
 | 
						|
 | 
						|
static struct sound_lowlev_timer gus_tmr =
 | 
						|
{
 | 
						|
	0,
 | 
						|
	1,
 | 
						|
	gus_tmr_start,
 | 
						|
	gus_tmr_disable,
 | 
						|
	gus_tmr_restart
 | 
						|
};
 | 
						|
 | 
						|
static void gus_tmr_install(int io_base)
 | 
						|
{
 | 
						|
	struct sound_lowlev_timer *tmr;
 | 
						|
 | 
						|
	select_addr = io_base;
 | 
						|
	data_addr = io_base + 1;
 | 
						|
 | 
						|
	tmr = &gus_tmr;
 | 
						|
 | 
						|
#ifdef THIS_GETS_FIXED
 | 
						|
	sound_timer_init(&gus_tmr, "GUS");
 | 
						|
#endif
 | 
						|
}
 |