* Driver for the Gravis UltraSound wave table synth.
* Copyright by Hannu Savolainen 1993
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. 2.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#include "sound_config.h"
#include <machine/ultrasound.h>
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
unsigned long current_freq
;
unsigned int initial_volume
;
unsigned int current_volume
;
int loop_irq_mode
, loop_irq_parm
;
int volume_irq_mode
, volume_irq_parm
;
#define VMODE_START_NOTE 3
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
;
extern int gus_irq
, gus_dma
;
extern char *snd_raw_buf
[MAX_DSP_DEV
][DSP_BUFFCOUNT
];
extern unsigned long snd_raw_buf_phys
[MAX_DSP_DEV
][DSP_BUFFCOUNT
];
extern int snd_raw_count
[MAX_DSP_DEV
];
static long gus_mem_size
= 0;
static long free_mem_ptr
= 0;
static int nr_voices
= 0;
static int gus_devnum
= 0;
static int volume_base
, volume_scale
, volume_method
;
static int gus_line_vol
= 100, gus_mic_vol
= 0;
static int gus_recmask
= SOUND_MASK_MIC
;
static int recording_active
= 0;
int gus_wave_volume
= 60;
static unsigned char mix_image
= 0x00;
* 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
= 0;
#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 the
static int gus_sampling_speed
;
static int gus_sampling_channels
;
static int gus_sampling_bits
;
DEFINE_WAIT_QUEUE (dram_sleeper
, dram_sleep_flag
);
* Variables and buffers for PCM output
#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /*
* * * * # bytes allocated for channels */
static int pcm_datasize
[MAX_PCM_BUFFERS
]; /*
* * * * Actual # of bytes
static volatile int pcm_head
, pcm_tail
, pcm_qlen
; /*
static volatile int pcm_active
;
static int pcm_opened
= 0;
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
;
struct voice_info voices
[32];
static int freq_div_table
[] =
static struct patch_info
*samples
;
static long sample_ptrs
[MAX_SAMPLE
+ 1];
static int sample_map
[32];
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);
#define INSTANT_RAMP -1 /*
* * * Dont use ramping */
* * * Fastest possible ramp */
reset_sample_memory (void)
for (i
= 0; i
<= MAX_SAMPLE
; i
++)
for (i
= 0; i
< MAX_PATCH
; i
++)
gus_poke (long addr
, unsigned char data
)
OUTB (addr
& 0xff, u_DataLo
);
OUTB ((addr
>> 8) & 0xff, u_DataHi
);
OUTB ((addr
>> 16) & 0xff, u_DataHi
);
OUTB (addr
& 0xff, u_DataLo
);
OUTB ((addr
>> 8) & 0xff, u_DataHi
);
OUTB ((addr
>> 16) & 0xff, u_DataHi
);
gus_write8 (int reg
, unsigned int data
)
OUTB ((unsigned char) (data
& 0xff), u_DataHi
);
OUTB (reg
| 0x80, u_Command
);
gus_write16 (int reg
, unsigned int data
)
OUTB ((unsigned char) (data
& 0xff), u_DataLo
);
OUTB ((unsigned char) ((data
>> 8) & 0xff), u_DataHi
);
OUTB (reg
| 0x80, u_Command
);
return ((hi
<< 8) & 0xff00) | lo
;
gus_write_addr (int reg
, unsigned long address
, int is16bit
)
unsigned long hold_address
;
* Special processing required for 16 bit patches
address
|= (hold_address
& 0x000c0000L
);
gus_write16 (reg
, (unsigned short) ((address
>> 7) & 0xffff));
gus_write16 (reg
+ 1, (unsigned short) ((address
<< 9) & 0xffff));
/* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
gus_write16 (reg
, (unsigned short) ((address
>> 7) & 0xffff));
gus_write16 (reg
+ 1, (unsigned short) ((address
<< 9) & 0xffff));
gus_select_voice (int voice
)
if (voice
< 0 || voice
> 31)
gus_select_max_voices (int nvoices
)
gus_write8 (0x0e, (nvoices
- 1) | 0xc0);
gus_voice_on (unsigned int mode
)
gus_write8 (0x00, (unsigned char) (mode
& 0xfc));
gus_write8 (0x00, (unsigned char) (mode
& 0xfc));
gus_write8 (0x00, gus_read8 (0x00) | 0x03);
gus_voice_mode (unsigned int m
)
unsigned char mode
= (unsigned char) (m
& 0xff);
gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode
& 0xfc)); /*
gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode
& 0xfc));
gus_voice_freq (unsigned long freq
)
unsigned long divisor
= freq_div_table
[nr_voices
- 14];
fc
= (unsigned short) (((freq
<< 9) + (divisor
>> 1)) / divisor
);
gus_voice_volume (unsigned int vol
)
gus_write8 (0x0d, 0x03); /*
* Stop ramp before setting volume
gus_write16 (0x09, (unsigned short) (vol
<< 4));
gus_voice_balance (unsigned int balance
)
gus_write8 (0x0c, (unsigned char) (balance
& 0xff));
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));
gus_ramp_rate (unsigned int scale
, unsigned int rate
)
gus_write8 (0x06, (unsigned char) (((scale
& 0x03) << 6) | (rate
& 0x3f)));
gus_rampon (unsigned int m
)
unsigned char mode
= (unsigned char) (m
& 0xff);
gus_write8 (0x0d, mode
& 0xfc);
gus_write8 (0x0d, mode
& 0xfc);
gus_ramp_mode (unsigned int m
)
unsigned char mode
= (unsigned char) (m
& 0xff);
gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode
& 0xfc)); /*
gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode
& 0xfc));
gus_set_voice_pos (int voice
, long position
)
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
;
gus_write_addr (0x0a, sample_ptrs
[sample_no
] + position
,
samples
[sample_no
].mode
& WAVE_16_BITS
);
gus_voice_init (int voice
)
gus_select_voice (voice
);
gus_write_addr (0x0a, 0, 0); /*
* Set current position to 0
gus_write8 (0x00, 0x03); /*
gus_write8 (0x0d, 0x03); /*
gus_voice_init2 (int voice
)
voices
[voice
].panning
= 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;
step_envelope (int voice
)
unsigned vol
, prev_vol
, phase
;
if (voices
[voice
].mode
& WAVE_SUSTAIN_ON
&& voices
[voice
].env_phase
== 2)
gus_select_voice (voice
);
if (voices
[voice
].env_phase
>= 5)
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
];
gus_select_voice (voice
);
gus_voice_volume (prev_vol
);
gus_write8 (0x06, rate
); /*
voices
[voice
].volume_irq_mode
= VMODE_ENVELOPE
;
if (((vol
- prev_vol
) / 64) == 0) /*
* No significant volume change
step_envelope (voice
); /*
* Continue with the next phase
gus_ramp_range (vol
, 4030);
voices
[voice
].current_volume
= vol
;
init_envelope (int voice
)
voices
[voice
].env_phase
= -1;
voices
[voice
].current_volume
= 64;
start_release (int voice
, long int flags
)
if (gus_read8 (0x00) & 0x03)
voices
[voice
].env_phase
= 2; /*
* Will be incremented by step_envelope
voices
[voice
].current_volume
=
voices
[voice
].initial_volume
=
gus_read16 (0x09) >> 4; /*
voices
[voice
].mode
&= ~WAVE_SUSTAIN_ON
;
gus_voice_fade (int voice
)
int instr_no
= sample_map
[voice
], is16bits
;
gus_select_voice (voice
);
if (instr_no
< 0 || instr_no
> MAX_SAMPLE
)
gus_write8 (0x00, 0x03); /*
is16bits
= (samples
[instr_no
].mode
& WAVE_16_BITS
) ? 1 : 0; /*
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
start_release (voice
, flags
);
* Ramp the volume down but not too quickly.
if ((gus_read16 (0x09) >> 4) < 100) /*
gus_ramp_range (65, 4030);
gus_rampon (0x40 | 0x20); /*
voices
[voice
].volume_irq_mode
= VMODE_HALT
;
gus_select_max_voices (24);
volume_method
= VOL_METHOD_ADAGIO
;
* Touch the status register
* Clear any pending DMA IRQs
* Clear any pending sample IRQs
register unsigned char dma_image
, irq_image
, tmp
;
static unsigned char gus_irq_map
[16] =
{0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
static unsigned char gus_dma_map
[8] =
{0, 1, 0, 2, 0, 3, 4, 5};
gus_select_max_voices (24);
* Touch the status register
* Clear any pending DMA IRQs
* Clear any pending sample IRQs
* Clear any pending DMA IRQs
* Clear any pending sample IRQs
* Master reset | DAC enable | IRQ enable
* Set up for Digital ASIC
OUTB (0x05, gus_base
+ 0x0f);
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
tmp
= gus_irq_map
[gus_irq
];
printk ("Warning! GUS IRQ not selected\n");
* Combine IRQ1 (GF1) and IRQ2 (Midi)
* Combine DMA1 (DRAM) and IRQ2 (ADC)
tmp
= gus_dma_map
[gus_dma
];
printk ("Warning! GUS DMA not selected\n");
* For some reason the IRQ and DMA addresses must be written twice
OUTB (mix_image
, u_Mixer
); /*
OUTB (dma_image
| 0x80, u_IRQDMAControl
); /*
OUTB (mix_image
| 0x40, u_Mixer
); /*
OUTB (irq_image
, u_IRQDMAControl
); /*
OUTB (mix_image
, u_Mixer
); /*
OUTB (dma_image
, u_IRQDMAControl
); /*
OUTB (mix_image
| 0x40, u_Mixer
); /*
OUTB (irq_image
, u_IRQDMAControl
); /*
* This disables writes to IRQ/DMA reg
OUTB (mix_image
, u_Mixer
); /*
* Note! Mic in is left off.
* This disables writes to IRQ/DMA reg
* Serve pending interrupts
gus_wave_detect (int baseaddr
)
gus_write8 (0x4c, 0); /* Reset GF1 */
gus_write8 (0x4c, 1); /* Release Reset */
/* See if there is first block there.... */
if (gus_peek (0L) != 0xaa)
/* Now zero it out so that I can check for mirroring .. */
for (i
= 1L; i
< 1024L; i
++)
/* check for mirroring ... */
for (n
= loc
- 1, failed
= 0; n
<= loc
; n
++)
if (gus_peek (loc
) != 0xaa)
if (gus_peek (loc
) != 0x55)
unsigned int cmd
, unsigned int arg
)
gus_info
.nr_voices
= nr_voices
;
IOCTL_TO_USER ((char *) arg
, 0, &gus_info
, sizeof (gus_info
));
case SNDCTL_SEQ_RESETSAMPLES
:
case SNDCTL_SEQ_PERCMODE
:
case SNDCTL_SYNTH_MEMAVL
:
return gus_mem_size
- free_mem_ptr
- 32;
return RET_ERROR (EINVAL
);
guswave_set_instr (int dev
, int voice
, int instr_no
)
if (instr_no
< 0 || instr_no
> MAX_PATCH
)
return RET_ERROR (EINVAL
);
if (voice
< 0 || voice
> 31)
return RET_ERROR (EINVAL
);
if (voices
[voice
].volume_irq_mode
== VMODE_START_NOTE
)
voices
[voice
].sample_pending
= instr_no
;
sample_no
= patch_table
[instr_no
];
printk ("GUS: Undefined patch %d for voice %d\n", instr_no
, voice
);
return RET_ERROR (EINVAL
);/*
if (sample_ptrs
[sample_no
] == -1) /*
printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no
, instr_no
, voice
);
return RET_ERROR (EINVAL
);
sample_map
[voice
] = sample_no
;
patch_map
[voice
] = instr_no
;
guswave_kill_note (int dev
, int voice
, int note
, int velocity
)
guswave_kill_note (int dev
, int voice
, int velocity
)
if (voices
[voice
].volume_irq_mode
== VMODE_START_NOTE
)
voices
[voice
].kill_pending
= 1;
guswave_aftertouch (int dev
, int voice
, int pressure
)
short lo_limit
, hi_limit
;
if (voice
< 0 || voice
> 31)
if (voices
[voice
].mode
& WAVE_ENVELOPES
&& voices
[voice
].env_phase
!= 2)
* Don't mix with envelopes
gus_select_voice (voice
);
compute_and_set_volume (voice
, 255, 0); /*
* Back to original volume
hi_limit
= voices
[voice
].current_volume
;
lo_limit
= hi_limit
* 99 / 100;
gus_select_voice (voice
);
if (hi_limit
> (4095 - 65))
gus_voice_volume (hi_limit
);
gus_ramp_range (lo_limit
, hi_limit
);
* Bidirectional, Down, Loop
guswave_panning (int dev
, int voice
, int value
)
if (voice
>= 0 || voice
< 32)
voices
[voice
].panning
= value
;
guswave_volume_method (int dev
, int mode
)
if (mode
== VOL_METHOD_LINEAR
|| mode
== VOL_METHOD_ADAGIO
)
compute_volume (int voice
, int volume
)
voices
[voice
].midi_volume
= volume
;
voices
[voice
].initial_volume
=
gus_adagio_vol (voices
[voice
].midi_volume
, voices
[voice
].main_vol
,
voices
[voice
].expression_vol
,
voices
[voice
].patch_vol
);
case VOL_METHOD_LINEAR
: /* Totally ignores patch-volume and expression */
voices
[voice
].initial_volume
=
gus_linear_vol (volume
, voices
[voice
].main_vol
);
voices
[voice
].initial_volume
= volume_base
+
(voices
[voice
].midi_volume
* volume_scale
);
if (voices
[voice
].initial_volume
> 4030)
voices
[voice
].initial_volume
= 4030;
compute_and_set_volume (int voice
, int volume
, int ramp_time
)
int current
, target
, rate
;
compute_volume (voice
, volume
);
voices
[voice
].current_volume
= voices
[voice
].initial_volume
;
* CAUTION! Interrupts disabled. Enable them before returning
gus_select_voice (voice
);
current
= gus_read16 (0x09) >> 4;
target
= voices
[voice
].initial_volume
;
if (ramp_time
== INSTANT_RAMP
)
gus_voice_volume (target
);
if (ramp_time
== FAST_RAMP
)
if ((target
- current
) / 64 == 0) /*
gus_voice_volume (target
);
if (target
> (4095 - 65))
gus_ramp_range (current
, target
);
gus_ramp_range (target
, current
);
* Ramp down, once, no irq
dynamic_volume_change (int voice
)
gus_select_voice (voice
);
status
= gus_read8 (0x00); /*
if (!(voices
[voice
].mode
& WAVE_ENVELOPES
))
compute_and_set_volume (voice
, voices
[voice
].midi_volume
, 1);
* Voice is running and has envelopes.
gus_select_voice (voice
);
status
= gus_read8 (0x0d); /*
compute_and_set_volume (voice
, voices
[voice
].midi_volume
, 1);
if (voices
[voice
].env_phase
< 0)
compute_volume (voice
, voices
[voice
].midi_volume
);
* * * Is this really required */
voices
[voice
].current_volume
=
gus_read16 (0x09) >> 4; /*
voices
[voice
].env_phase
--;
guswave_controller (int dev
, int voice
, int ctrl_num
, int value
)
if (voice
< 0 || voice
> 31)
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
);
voices
[voice
].current_freq
= freq
;
gus_select_voice (voice
);
case CTRL_PITCH_BENDER_RANGE
:
voices
[voice
].bender_range
= value
;
if (volume_method
== VOL_METHOD_ADAGIO
)
voices
[voice
].expression_vol
= value
;
if (voices
[voice
].volume_irq_mode
!= VMODE_START_NOTE
)
dynamic_volume_change (voice
);
voices
[voice
].panning
= (value
* 2) - 128;
value
= (value
* 100) / 16383;
voices
[voice
].main_vol
= value
;
if (voices
[voice
].volume_irq_mode
!= VMODE_START_NOTE
)
dynamic_volume_change (voice
);
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
;
if (voice
< 0 || voice
> 31)
printk ("GUS: Invalid voice\n");
return RET_ERROR (EINVAL
);
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
voices
[voice
].midi_volume
= volume
;
dynamic_volume_change (voice
);
compute_and_set_volume (voice
, volume
, 1);
if ((patch
= patch_map
[voice
]) == -1)
return RET_ERROR (EINVAL
);
if ((samplep
= patch_table
[patch
]) == -1)
return RET_ERROR (EINVAL
);
note_freq
= note_to_freq (note_num
);
* Find a sample within a patch so that the note_freq is between low_note
while (samplep
>= 0 && sample
== -1)
delta_freq
= note_freq
- samples
[samplep
].base_note
;
delta_freq
= -delta_freq
;
if (delta_freq
< best_delta
)
if (samples
[samplep
].low_note
<= note_freq
&& note_freq
<= samples
[samplep
].high_note
)
samplep
= samples
[samplep
].key
; /*
printk ("GUS: Patch %d not defined for note %d\n", patch
, note_num
);
* 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 (voices
[voice
].mode
& WAVE_ENVELOPES
)
voices
[voice
].env_rate
[i
] = samples
[sample
].env_rate
[i
];
voices
[voice
].env_offset
[i
] = samples
[sample
].env_offset
[i
];
sample_map
[voice
] = sample
;
base_note
= samples
[sample
].base_note
/ 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
);
voices
[voice
].current_freq
= freq
;
pan
= (samples
[sample
].panning
+ voices
[voice
].panning
) / 32;
if (samples
[sample
].mode
& WAVE_16_BITS
)
if ((sample_ptrs
[sample
] >> 18) !=
((sample_ptrs
[sample
] + samples
[sample
].len
) >> 18))
printk ("GUS: Sample address error\n");
/*************************************************************************
* CAUTION! Interrupts disabled. Don't return before enabling
*************************************************************************/
gus_select_voice (voice
);
* It may still be running
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
compute_volume (voice
, volume
);
compute_and_set_volume (voice
, volume
, 0);
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
, is16bits
); /* Sample
gus_write_addr (0x0a, sample_ptrs
[sample
] + voices
[voice
].offset_pending
,
is16bits
); /* Sample start=begin */
if (samples
[sample
].mode
& WAVE_LOOPING
)
if (samples
[sample
].mode
& WAVE_BIDIR_LOOP
)
* Bidirectional looping on
if (samples
[sample
].mode
& WAVE_LOOP_BACK
)
sample_ptrs
[sample
] + samples
[sample
].loop_end
-
voices
[voice
].offset_pending
, is16bits
);
gus_write_addr (0x02, sample_ptrs
[sample
] + samples
[sample
].loop_start
, is16bits
); /*
gus_write_addr (0x04, sample_ptrs
[sample
] + samples
[sample
].loop_end
, is16bits
); /*
voices
[voice
].loop_irq_mode
= LMODE_FINISH
; /*
voices
[voice
].loop_irq_parm
= 1;
gus_write_addr (0x02, sample_ptrs
[sample
], is16bits
); /*
gus_write_addr (0x04, sample_ptrs
[sample
] + samples
[sample
].len
- 1, is16bits
); /*
* * New guswave_start_note by Andrew J. Robinson attempts to minimize
* clicking * when the note playing on the voice is changed. It uses volume
guswave_start_note (int dev
, int voice
, int note_num
, int volume
)
if (voices
[voice
].volume_irq_mode
== VMODE_START_NOTE
)
voices
[voice
].volume_pending
= volume
;
ret_val
= guswave_start_note2 (dev
, voice
, note_num
, volume
);
gus_select_voice (voice
);
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)
guswave_set_instr (voices
[voice
].dev_pending
, voice
,
voices
[voice
].sample_pending
);
voices
[voice
].sample_pending
= -1;
if ((mode
& 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
ret_val
= guswave_start_note2 (dev
, voice
, note_num
, volume
);
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_ramp_range (2000, 4065);
gus_ramp_rate (0, 63);/* Fastest possible rate */
gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
guswave_open (int dev
, int mode
)
return RET_ERROR (EBUSY
);
if ((err
= DMAbuf_open_dma (gus_devnum
)))
RESET_WAIT_QUEUE (dram_sleeper
, dram_sleep_flag
);
active_device
= GUS_DEV_WAVE
;
DMAbuf_close_dma (gus_devnum
);
guswave_load_patch (int dev
, int format
, snd_rw_buf
* addr
,
int offs
, int count
, int pmgr_flag
)
unsigned long blk_size
, blk_end
, left
, src_offs
, target
;
sizeof_patch
= (long) &patch
.data
[0] - (long) &patch
; /*
printk ("GUS Error: Invalid patch format (key) 0x%x\n", format
);
return RET_ERROR (EINVAL
);
if (count
< sizeof_patch
)
printk ("GUS Error: Patch header too short\n");
return RET_ERROR (EINVAL
);
if (free_sample
>= MAX_SAMPLE
)
printk ("GUS: Sample table full\n");
return RET_ERROR (ENOSPC
);
* Copy the header from user space but ignore the first bytes which have
* been transferred already.
COPY_FROM_USER (&((char *) &patch
)[offs
], addr
, offs
, sizeof_patch
- offs
);
if (instr
< 0 || instr
> MAX_PATCH
)
printk ("GUS: Invalid patch number %d\n", instr
);
return RET_ERROR (EINVAL
);
printk ("GUS Warning: Patch record too short (%d<%d)\n",
if (patch
.len
<= 0 || patch
.len
> gus_mem_size
)
printk ("GUS: Invalid sample length %d\n", (int) patch
.len
);
return RET_ERROR (EINVAL
);
if (patch
.mode
& WAVE_LOOPING
)
if (patch
.loop_start
< 0 || patch
.loop_start
>= patch
.len
)
printk ("GUS: Invalid loop start\n");
return RET_ERROR (EINVAL
);
if (patch
.loop_end
< patch
.loop_start
|| patch
.loop_end
> patch
.len
)
printk ("GUS: Invalid loop end\n");
return RET_ERROR (EINVAL
);
free_mem_ptr
= (free_mem_ptr
+ 31) & ~31; /*
#define GUS_BANK_SIZE (256*1024)
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 RET_ERROR (ENOSPC
);
if ((free_mem_ptr
/ GUS_BANK_SIZE
) !=
((free_mem_ptr
+ patch
.len
) / GUS_BANK_SIZE
))
unsigned long tmp_mem
= /*
((free_mem_ptr
/ GUS_BANK_SIZE
) + 1) * GUS_BANK_SIZE
;
if ((tmp_mem
+ patch
.len
) > gus_mem_size
)
return RET_ERROR (ENOSPC
);
free_mem_ptr
= tmp_mem
; /*
* This leaves unusable memory
if ((free_mem_ptr
+ patch
.len
) > gus_mem_size
)
return RET_ERROR (ENOSPC
);
sample_ptrs
[free_sample
] = free_mem_ptr
;
* Tremolo is not possible with envelopes
if (patch
.mode
& WAVE_ENVELOPES
)
patch
.mode
&= ~WAVE_TREMOLO
;
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
blk_size
= sound_buffsizes
[gus_devnum
];
* DMA cannot cross 256k bank boundaries. Check for that.
blk_end
= target
+ blk_size
;
if ((target
>> 18) != (blk_end
>> 18))
* Have to split the block
blk_end
&= ~(256 * 1024 - 1);
blk_size
= blk_end
- target
;
#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
* For some reason the DMA is not possible. We have to use PIO.
for (i
= 0; i
< blk_size
; i
++)
GET_BYTE_FROM_USER (data
, addr
, sizeof_patch
+ i
);
if (patch
.mode
& WAVE_UNSIGNED
)
if (!(patch
.mode
& WAVE_16_BITS
) || (i
& 0x01))
gus_poke (target
+ i
, data
);
unsigned long address
, hold_address
;
unsigned char dma_command
;
* OK, move now. First in and then out.
COPY_FROM_USER (snd_raw_buf
[gus_devnum
][0],
addr
, sizeof_patch
+ src_offs
,
DISABLE_INTR (flags
); /******** INTERRUPTS DISABLED NOW ********/
DMAbuf_start_dma (gus_devnum
, snd_raw_buf_phys
[gus_devnum
][0],
blk_size
, DMA_MODE_WRITE
);
* Set the DRAM address for the wave data
if (sound_dsp_dmachan
[gus_devnum
] > 3)
address
|= (hold_address
& 0x000c0000L
);
gus_write16 (0x42, (address
>> 4) & 0xffff); /*
if (patch
.mode
& WAVE_UNSIGNED
)
if (patch
.mode
& WAVE_16_BITS
)
if (sound_dsp_dmachan
[gus_devnum
] > 3)
gus_write8 (0x41, dma_command
); /*
* Let's go luteet (=bugs)
* Sleep here until the DRAM DMA done interrupt is served
active_device
= GUS_DEV_WAVE
;
DO_SLEEP (dram_sleeper
, dram_sleep_flag
, HZ
);
if (TIMED_OUT (dram_sleeper
, dram_sleep_flag
))
printk ("GUS: DMA Transfer timed out\n");
free_mem_ptr
+= patch
.len
;
pmgr_inform (dev
, PM_E_PATCH_LOADED
, instr
, free_sample
, 0, 0);
guswave_hw_control (int dev
, unsigned char *event
)
unsigned long plong
, flags
;
p1
= *(unsigned short *) &event
[4];
p2
= *(unsigned short *) &event
[6];
plong
= *(unsigned long *) &event
[4];
if ((voices
[voice
].volume_irq_mode
== VMODE_START_NOTE
) &&
(cmd
!= _GUS_VOICESAMPLE
) && (cmd
!= _GUS_VOICE_POS
))
gus_select_voice (voice
);
gus_select_max_voices (p1
);
guswave_set_instr (dev
, voice
, p1
);
gus_select_voice (voice
);
gus_select_voice (voice
);
gus_select_voice (voice
);
gus_select_voice (voice
);
gus_select_voice (voice
);
gus_select_voice (voice
);
* Just update the voice value
voices
[voice
].initial_volume
=
voices
[voice
].current_volume
= p1
;
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
gus_select_voice (voice
);
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
gus_select_voice (voice
);
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
gus_select_voice (voice
);
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
gus_select_voice (voice
);
if (voices
[voice
].mode
& WAVE_ENVELOPES
)
gus_select_voice (voice
);
gus_select_voice (voice
);
gus_set_voice_pos (voice
, plong
);
gus_sampling_set_speed (int speed
)
return gus_sampling_speed
;
gus_sampling_speed
= speed
;
gus_sampling_set_channels (int channels
)
return gus_sampling_channels
;
gus_sampling_channels
= channels
;
gus_sampling_set_bits (int bits
)
return gus_sampling_bits
;
if (bits
!= 8 && bits
!= 16)
gus_sampling_bits
= bits
;
gus_sampling_ioctl (int dev
, unsigned int cmd
, unsigned int arg
, int local
)
case SOUND_PCM_WRITE_RATE
:
return gus_sampling_set_speed (arg
);
return IOCTL_OUT (arg
, gus_sampling_set_speed (IOCTL_IN (arg
)));
case SOUND_PCM_READ_RATE
:
return gus_sampling_speed
;
return IOCTL_OUT (arg
, gus_sampling_speed
);
return gus_sampling_set_channels (arg
+ 1) - 1;
return IOCTL_OUT (arg
, gus_sampling_set_channels (IOCTL_IN (arg
) + 1) - 1);
case SOUND_PCM_WRITE_CHANNELS
:
return gus_sampling_set_channels (arg
);
return IOCTL_OUT (arg
, gus_sampling_set_channels (IOCTL_IN (arg
)));
case SOUND_PCM_READ_CHANNELS
:
return gus_sampling_channels
;
return IOCTL_OUT (arg
, gus_sampling_channels
);
case SNDCTL_DSP_SAMPLESIZE
:
return gus_sampling_set_bits (arg
);
return IOCTL_OUT (arg
, gus_sampling_set_bits (IOCTL_IN (arg
)));
case SOUND_PCM_READ_BITS
:
return gus_sampling_bits
;
return IOCTL_OUT (arg
, gus_sampling_bits
);
case SOUND_PCM_WRITE_FILTER
: /*
return IOCTL_OUT (arg
, RET_ERROR (EINVAL
));
case SOUND_PCM_READ_FILTER
:
return IOCTL_OUT (arg
, RET_ERROR (EINVAL
));
return RET_ERROR (EINVAL
);
return RET_ERROR (EINVAL
);
gus_sampling_reset (int dev
)
gus_sampling_open (int dev
, int mode
)
printk ("GUS: DMA mode not enabled. Device not supported\n");
return RET_ERROR (ENXIO
);
return RET_ERROR (EBUSY
);
gus_select_max_voices (14);
gus_sampling_close (int dev
)
gus_sampling_update_volume (void)
if (pcm_active
&& pcm_opened
)
for (voice
= 0; voice
< gus_sampling_channels
; voice
++)
gus_select_voice (voice
);
gus_voice_volume (1530 + (25 * gus_pcm_volume
));
gus_ramp_range (65, 1530 + (25 * gus_pcm_volume
));
play_next_pcm_block (void)
int speed
= gus_sampling_speed
;
int this_one
, is16bits
, chn
;
unsigned char mode
[2], ramp_mode
[2];
for (chn
= 0; chn
< gus_sampling_channels
; chn
++)
ramp_mode
[chn
] = 0x03; /*
* Ramping and rollover off
voices
[chn
].loop_irq_mode
= LMODE_PCM
;
if (gus_sampling_bits
!= 8)
dram_loc
= this_one
* pcm_bsize
;
dram_loc
+= chn
* pcm_banksize
;
if (this_one
== (pcm_nblk
- 1)) /*
* Last of the DRAM buffers
ramp_mode
[chn
] = 0x04; /*
if (gus_sampling_channels
== 1)
gus_voice_balance (7); /*
gus_voice_balance (0); /*
gus_voice_balance (15); /*
* 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.
* It could already be running
gus_voice_volume (1530 + (25 * gus_pcm_volume
));
gus_ramp_range (65, 1530 + (25 * gus_pcm_volume
));
gus_write_addr (0x0a, dram_loc
, is16bits
); /*
gus_write_addr (0x02, chn
* pcm_banksize
, is16bits
); /*
gus_write_addr (0x04, pcm_banksize
+ (pcm_bsize
* pcm_nblk
),
gus_write_addr (0x04, dram_loc
+ pcm_datasize
[this_one
], is16bits
); /*
if (pcm_datasize
[this_one
] != pcm_bsize
)
* Incomplete block. Possibly the last one.
voices
[0].loop_irq_mode
= LMODE_PCM_STOP
;
ramp_mode
[chn
] = 0x03; /*
gus_write_addr (0x04, dram_loc
+ pcm_datasize
[this_one
], is16bits
); /*
for (chn
= 0; chn
< gus_sampling_channels
; chn
++)
gus_write8 (0x0d, ramp_mode
[chn
]);
gus_voice_on (mode
[chn
]);
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.
unsigned char dma_command
;
unsigned long address
, hold_address
;
count
= total_count
/ gus_sampling_channels
;
if (pcm_qlen
>= pcm_nblk
)
printk ("GUS Warning: PCM buffers out of sync\n");
this_one
= pcm_current_block
= pcm_tail
;
pcm_tail
= (pcm_tail
+ 1) % pcm_nblk
;
pcm_datasize
[this_one
] = count
;
this_one
= pcm_current_block
;
DMAbuf_start_dma (dev
, buf
+ (chn
* count
), count
, DMA_MODE_WRITE
);
address
= this_one
* pcm_bsize
;
address
+= chn
* pcm_banksize
;
if (sound_dsp_dmachan
[dev
] > 3)
address
|= (hold_address
& 0x000c0000L
);
gus_write16 (0x42, (address
>> 4) & 0xffff); /*
if (gus_sampling_bits
!= 8)
if (sound_dsp_dmachan
[dev
] > 3)
gus_write8 (0x41, dma_command
); /*
if (chn
== (gus_sampling_channels
- 1)) /*
* Last (right or mono) channel data
active_device
= GUS_DEV_PCM_DONE
;
if (!pcm_active
&& (pcm_qlen
> 2 || count
< pcm_bsize
))
* * * Left channel data. The right channel
* is * * * transferred after DMA interrupt */
active_device
= GUS_DEV_PCM_CONTINUE
;
gus_sampling_output_block (int dev
, unsigned long buf
, int total_count
,
int intrflag
, int restart_dma
)
pcm_current_count
= total_count
;
pcm_current_intrflag
= intrflag
;
gus_transfer_output_block (dev
, buf
, total_count
, intrflag
, 0);
gus_sampling_start_input (int dev
, unsigned long buf
, int count
,
int intrflag
, int restart_dma
)
DMAbuf_start_dma (dev
, buf
, count
, DMA_MODE_READ
);
* DMA IRQ enable, invert MSB
if (sound_dsp_dmachan
[dev
] > 3)
if (gus_sampling_channels
> 1)
gus_sampling_prepare_for_input (int dev
, int bsize
, int bcount
)
rate
= (9878400 / (gus_sampling_speed
+ 2)) / 16;
gus_write8 (0x48, rate
& 0xff); /*
if (gus_sampling_bits
!= 8)
printk ("GUS Error: 16 bit recording not supported\n");
return RET_ERROR (EINVAL
);
gus_sampling_prepare_for_output (int dev
, int bsize
, int bcount
)
mem_size
= gus_mem_size
/ gus_sampling_channels
;
if (mem_size
> (256 * 1024))
pcm_bsize
= bsize
/ gus_sampling_channels
;
pcm_head
= pcm_tail
= pcm_qlen
= 0;
pcm_nblk
= MAX_PCM_BUFFERS
;
if ((pcm_bsize
* pcm_nblk
) > mem_size
)
pcm_nblk
= mem_size
/ pcm_bsize
;
for (i
= 0; i
< pcm_nblk
; i
++)
pcm_banksize
= pcm_nblk
* pcm_bsize
;
if (gus_sampling_bits
!= 8 && pcm_banksize
== (256 * 1024))
gus_has_output_drained (int dev
)
gus_copy_from_user (int dev
, char *localbuf
, int localoffs
,
snd_rw_buf
* userbuf
, int useroffs
, int len
)
if (gus_sampling_channels
== 1)
COPY_FROM_USER (&localbuf
[localoffs
], userbuf
, useroffs
, len
);
else if (gus_sampling_bits
== 8)
int in_right
= useroffs
+ 1;
char *out_left
, *out_right
;
out_left
= &localbuf
[localoffs
];
out_right
= out_left
+ pcm_bsize
;
for (i
= 0; i
< len
; i
++)
GET_BYTE_FROM_USER (*out_left
++, userbuf
, in_left
);
GET_BYTE_FROM_USER (*out_right
++, userbuf
, in_right
);
int in_right
= useroffs
+ 1;
short *out_left
, *out_right
;
out_left
= (short *) &localbuf
[localoffs
];
out_right
= out_left
+ (pcm_bsize
/ 2);
for (i
= 0; i
< len
; i
++)
GET_SHORT_FROM_USER (*out_left
++, (short *) userbuf
, in_left
);
GET_SHORT_FROM_USER (*out_right
++, (short *) userbuf
, in_right
);
static struct audio_operations gus_sampling_operations
=
gus_sampling_output_block
,
gus_sampling_start_input
,
gus_sampling_prepare_for_input
,
gus_sampling_prepare_for_output
,
guswave_bender (int dev
, int voice
, int value
)
voices
[voice
].bender
= value
- 8192;
freq
= compute_finetune (voices
[voice
].orig_freq
, value
, voices
[voice
].bender_range
);
voices
[voice
].current_freq
= freq
;
gus_select_voice (voice
);
guswave_patchmgr (int dev
, struct patmgr_info
*rec
)
rec
->parm1
= PMTYPE_WAVE
;
for (i
= 0; i
< MAX_PATCH
; i
++)
int ptr
= patch_table
[i
];
while (ptr
>= 0 && ptr
< free_sample
)
ptr
= samples
[ptr
].key
; /*
int ptr
= patch_table
[rec
->parm1
];
while (ptr
>= 0 && ptr
< free_sample
)
rec
->data
.data32
[n
++] = ptr
;
ptr
= samples
[ptr
].key
; /*
if (ptr
< 0 || ptr
>= free_sample
)
return RET_ERROR (EINVAL
);
memcpy (rec
->data
.data8
, (char *) &samples
[ptr
],
sizeof (struct patch_info
));
pat
= (struct patch_info
*) rec
->data
.data8
;
rec
->parm1
= sample_ptrs
[ptr
]; /*
rec
->parm2
= sizeof (struct patch_info
);
if (ptr
< 0 || ptr
>= free_sample
)
return RET_ERROR (EINVAL
);
pat
= (struct patch_info
*) rec
->data
.data8
;
if (pat
->len
> samples
[ptr
].len
) /*
return RET_ERROR (EINVAL
);
pat
->key
= samples
[ptr
].key
; /*
* Ensure the link is correct
memcpy ((char *) &samples
[ptr
], rec
->data
.data8
,
sizeof (struct patch_info
));
* Returns a block of wave data from the DRAM
if (sample
< 0 || sample
>= free_sample
)
return RET_ERROR (EINVAL
);
if (offs
< 0 || offs
>= samples
[sample
].len
)
return RET_ERROR (EINVAL
); /*
n
= samples
[sample
].len
- offs
; /*
if (l
> sizeof (rec
->data
.data8
))
l
= sizeof (rec
->data
.data8
);
return RET_ERROR (EINVAL
); /*
offs
+= sample_ptrs
[sample
]; /*
* Begin offsess + offset to DRAM
rec
->data
.data8
[n
] = gus_peek (offs
++);
* Writes a block of wave data to the DRAM
if (sample
< 0 || sample
>= free_sample
)
return RET_ERROR (EINVAL
);
if (offs
< 0 || offs
>= samples
[sample
].len
)
return RET_ERROR (EINVAL
); /*
n
= samples
[sample
].len
- offs
; /*
if (l
> sizeof (rec
->data
.data8
))
l
= sizeof (rec
->data
.data8
);
return RET_ERROR (EINVAL
); /*
offs
+= sample_ptrs
[sample
]; /*
* Begin offsess + offset to DRAM
gus_poke (offs
++, rec
->data
.data8
[n
]);
return RET_ERROR (EINVAL
);
static struct synth_operations guswave_operations
=
unsigned char mask
= 0xff & ~0x06; /* Just line out enabled */
* Enable channels having vol > 10%
* Note! bit 0x01 means line in DISABLED while 0x04 means
* Disable channel, if not selected for recording
if (!(gus_recmask
& SOUND_MASK_LINE
))
if (!(gus_recmask
& SOUND_MASK_MIC
))
mix_image
|= mask
& 0x07;
OUTB (mix_image
, u_Mixer
);
gus_default_mixer_ioctl (int dev
, unsigned int cmd
, unsigned int arg
)
#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
SOUND_MASK_SYNTH|SOUND_MASK_PCM)
if (((cmd
>> 8) & 0xff) == 'M')
gus_recmask
= IOCTL_IN (arg
) & 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 */
return IOCTL_OUT (arg
, gus_recmask
);
int vol
= IOCTL_IN (arg
) & 0xff;
return IOCTL_OUT (arg
, vol
| (vol
<< 8));
int vol
= IOCTL_IN (arg
) & 0xff;
return IOCTL_OUT (arg
, vol
| (vol
<< 8));
gus_pcm_volume
= IOCTL_IN (arg
) & 0xff;
if (gus_pcm_volume
> 100)
gus_sampling_update_volume ();
return IOCTL_OUT (arg
, gus_pcm_volume
| (gus_pcm_volume
<< 8));
gus_wave_volume
= IOCTL_IN (arg
) & 0xff;
if (gus_wave_volume
> 100)
if (active_device
== GUS_DEV_WAVE
)
for (voice
= 0; voice
< nr_voices
; voice
++)
dynamic_volume_change (voice
); /*
return IOCTL_OUT (arg
, gus_wave_volume
| (gus_wave_volume
<< 8));
return RET_ERROR (EINVAL
);
return IOCTL_OUT (arg
, gus_recmask
);
case SOUND_MIXER_DEVMASK
:
return IOCTL_OUT (arg
, MIX_DEVS
);
case SOUND_MIXER_STEREODEVS
:
return IOCTL_OUT (arg
, 0);
case SOUND_MIXER_RECMASK
:
return IOCTL_OUT (arg
, SOUND_MASK_MIC
| SOUND_MASK_LINE
);
return IOCTL_OUT (arg
, 0);
return IOCTL_OUT (arg
, gus_mic_vol
| (gus_mic_vol
<< 8));
return IOCTL_OUT (arg
, gus_line_vol
| (gus_line_vol
<< 8));
return IOCTL_OUT (arg
, gus_pcm_volume
| (gus_pcm_volume
<< 8));
return IOCTL_OUT (arg
, gus_wave_volume
| (gus_wave_volume
<< 8));
return RET_ERROR (EINVAL
);
return RET_ERROR (EINVAL
);
static struct mixer_operations gus_mixer_operations
=
gus_default_mixer_init (long mem_start
)
if (num_mixers
< MAX_MIXER_DEV
) /*
* Don't install if there is another
mixer_devs
[num_mixers
++] = &gus_mixer_operations
;
gus_wave_init (long mem_start
, int irq
, int dma
)
int gus_type
= 0x24; /* 2.4 */
* Try to identify the GUS model.
* Versions < 3.6 don't have the digital ASIC. Try to probe it first.
OUTB (0x20, gus_base
+ 0x0f);
val
= INB (gus_base
+ 0x0f);
if (val
!= 0xff && (val
& 0x06)) /* Should be 0x02? */
* It has the digital ASIC so the card is at least v3.4.
* Next try to detect the true model.
* 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.
* Sorry. No GUS max support yet but it should be available
* soon after the SDK for GUS MAX is available.
if (val
== 255 || val
< 5)
* ASIC not detected so the card must be 2.2 or 2.4.
* There could still be the 16-bit/mixer daughter card.
* It has the same codec/mixer than MAX.
* At this time there is no support for it but it will appear soon.
printk ("snd4: <Gravis UltraSound %s (%dk)>", model_num
, (int) gus_mem_size
/ 1024);
printk (" <Gravis UltraSound %s (%dk)>", model_num
, (int) gus_mem_size
/ 1024);
sprintf (gus_info
.name
, "Gravis UltraSound %s (%dk)", model_num
, (int) gus_mem_size
/ 1024);
printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq
);
printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma
);
if (num_synths
>= MAX_SYNTH_DEV
)
printk ("GUS Error: Too many synthesizers\n");
synth_devs
[num_synths
++] = &guswave_operations
;
PERMANENT_MALLOC (struct patch_info
*, samples
,
(MAX_SAMPLE
+ 1) * sizeof (*samples
), mem_start
);
if (num_dspdevs
< MAX_DSP_DEV
)
dsp_devs
[gus_devnum
= num_dspdevs
++] = &gus_sampling_operations
;
sound_dsp_dmachan
[gus_devnum
] = dma
;
sound_buffcounts
[gus_devnum
] = DSP_BUFFCOUNT
;
sound_buffsizes
[gus_devnum
] = DSP_BUFFSIZE
;
sound_dma_automode
[gus_devnum
] = 0;
printk ("GUS: Too many PCM devices available\n");
* Mixer dependent initialization.
gus_line_vol
=gus_mic_vol
=gus_wave_volume
= gus_pcm_volume
= 100;
return ics2101_mixer_init (mem_start
);
return gus_default_mixer_init (mem_start
);
gus_select_voice (voice
);
* Disable wave IRQ for this_one voice
mode
= voices
[voice
].loop_irq_mode
;
voices
[voice
].loop_irq_mode
= 0;
parm
= voices
[voice
].loop_irq_parm
;
* Final loop finished, shoot volume down
if ((gus_read16 (0x09) >> 4) < 100) /*
gus_ramp_range (65, 4065);
gus_ramp_rate (0, 63); /*
gus_rampon (0x20 | 0x40); /*
voices
[voice
].volume_irq_mode
= VMODE_HALT
;
* Requires extensive processing
int orig_qlen
= pcm_qlen
;
pcm_head
= (pcm_head
+ 1) % pcm_nblk
;
* Out of data. Just stop the voice
if (orig_qlen
== pcm_nblk
)
DMAbuf_outputintr (gus_devnum
, 0);
do_volume_irq (int voice
)
gus_select_voice (voice
);
* Disable volume ramp IRQ
mode
= voices
[voice
].volume_irq_mode
;
voices
[voice
].volume_irq_mode
= 0;
parm
= voices
[voice
].volume_irq_parm
;
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
, 0);
if (voices
[voice
].sample_pending
>= 0)
guswave_set_instr (voices
[voice
].dev_pending
, voice
,
voices
[voice
].sample_pending
);
voices
[voice
].sample_pending
= -1;
unsigned long wave_ignore
= 0, volume_ignore
= 0;
unsigned char src
, voice
;
src
= gus_read8 (0x0f); /*
if (src
== (0x80 | 0x40))
if (!(wave_ignore
& voice_bit
) && voice
< nr_voices
) /*
wave_ignore
|= voice_bit
;
if (!(volume_ignore
& voice_bit
) && voice
< nr_voices
) /*
volume_ignore
|= voice_bit
;
status
= gus_look8 (0x41); /*
if (SOMEONE_WAITING (dram_sleeper
, dram_sleep_flag
))
WAKE_UP (dram_sleeper
, dram_sleep_flag
);
case GUS_DEV_PCM_CONTINUE
:
gus_transfer_output_block (pcm_current_dev
, pcm_current_buf
,
pcm_current_intrflag
, 1);
DMAbuf_outputintr (gus_devnum
, pcm_qlen
== 0);
status
= gus_look8 (0x49); /*
* Get Sampling IRQ Status
DMAbuf_inputintr (gus_devnum
);