summaryrefslogtreecommitdiffstats
path: root/drivers/sound/gus_wave.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sound/gus_wave.c')
-rw-r--r--drivers/sound/gus_wave.c274
1 files changed, 151 insertions, 123 deletions
diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c
index 5c579b846..8c1523750 100644
--- a/drivers/sound/gus_wave.c
+++ b/drivers/sound/gus_wave.c
@@ -21,7 +21,7 @@
#if defined(CONFIG_GUSHW)
-#define GUS_BANK_SIZE (256*1024)
+#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
#define MAX_SAMPLE 150
#define MAX_PATCH 256
@@ -73,6 +73,7 @@ extern int gus_pnp_flag;
static int gus_dma2 = -1;
static int dual_dma_mode = 0;
static long gus_mem_size = 0;
+static long gus_rom_size = 0;
static long free_mem_ptr = 0;
static int gus_busy = 0;
static int gus_no_dma = 0;
@@ -84,6 +85,7 @@ static int recording_active = 0;
static int only_read_access = 0;
static int only_8_bits = 0;
+int iw_mode = 0;
int gus_wave_volume = 60;
int gus_pcm_volume = 80;
int have_gus_max = 0;
@@ -105,6 +107,8 @@ static int active_device = 0;
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 struct wait_queue *dram_sleeper = NULL;
static volatile struct snd_wait dram_sleep_flag =
@@ -113,7 +117,7 @@ static volatile struct snd_wait dram_sleep_flag =
/*
* Variables and buffers for PCM output
*/
-#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* Don't change */
+#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];
@@ -356,14 +360,22 @@ gus_write_addr (int reg, unsigned long address, int frac, int is16bit)
cli ();
if (is16bit)
{
- /*
- * Special processing required for 16 bit patches
- */
+ 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);
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
}
gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
@@ -389,6 +401,8 @@ gus_select_voice (int voice)
static void
gus_select_max_voices (int nvoices)
{
+ if (iw_mode)
+ nvoices = 32;
if (nvoices < 14)
nvoices = 14;
if (nvoices > 32)
@@ -430,7 +444,11 @@ gus_voice_freq (unsigned long freq)
unsigned long divisor = freq_div_table[nr_voices - 14];
unsigned short fc;
- fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
+ /* 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);
@@ -851,6 +869,8 @@ gus_initialize (void)
gus_read8 (0x0f); /* Clear pending IRQs */
+ if (iw_mode)
+ gus_write8 (0x19, gus_read8 (0x19) | 0x01);
restore_flags (flags);
}
@@ -1022,10 +1042,10 @@ pnp_mem_init (void)
*/
gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | bits);
-/*
- * Return the chip back to GUS compatible mode.
- */
- gus_write8 (0x19, gus_read8 (0x19) & ~0x01);
+/* Leave the chip into enhanced mode. Disable LFO */
+ gus_mem_size = total;
+ iw_mode = 1;
+ gus_write8 (0x19, (gus_read8 (0x19) | 0x01) & ~0x02);
}
int
@@ -1065,6 +1085,8 @@ gus_wave_detect (int baseaddr)
if (gus_pnp_flag)
pnp_mem_init ();
+ if (iw_mode)
+ return 1;
/* See if there is first block there.... */
gus_poke (0L, 0xaa);
@@ -1479,6 +1501,9 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
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;
@@ -1897,7 +1922,7 @@ guswave_load_patch (int dev, int format, const char *addr,
for (i = 0; i < blk_sz; i++)
{
- get_user (data, (unsigned char *) &((addr)[sizeof_patch + i]));
+ get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i]));
if (patch.mode & WAVE_UNSIGNED)
if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
data ^= 0x80; /* Convert to signed */
@@ -1934,17 +1959,37 @@ guswave_load_patch (int dev, int format, const char *addr,
* Set the DRAM address for the wave data
*/
- address = target;
-
- if (audio_devs[gus_devnum]->dmap_out->dma > 3)
+ if (iw_mode)
{
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
+ /* 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 */
+ gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+ }
/*
* Start the DMA transfer
@@ -2280,6 +2325,7 @@ gus_audio_reset (int dev)
}
}
+static int saved_iw_mode; /* A hack hack hack */
static int
gus_audio_open (int dev, int mode)
@@ -2300,6 +2346,13 @@ gus_audio_open (int dev, int mode)
gus_reset ();
reset_sample_memory ();
gus_select_max_voices (14);
+ 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;
+ }
pcm_active = 0;
dma_active = 0;
@@ -2322,6 +2375,7 @@ gus_audio_open (int dev, int mode)
static void
gus_audio_close (int dev)
{
+ iw_mode = saved_iw_mode;
gus_reset ();
gus_busy = 0;
pcm_opened = 0;
@@ -2428,7 +2482,7 @@ play_next_pcm_block (void)
gus_voice_volume (1530 + (25 * gus_pcm_volume));
gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
- gus_write_addr (0x0a, dram_loc, 0, is16bits); /* Starting position */
+ 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)
@@ -2437,30 +2491,11 @@ play_next_pcm_block (void)
}
if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1,
+ gus_write_addr (0x04, dram_loc + pcm_bsize - 1,
0, is16bits); /* Loop end location */
else
mode[chn] |= 0x08; /* Enable looping */
- if (pcm_datasize[this_one] != pcm_bsize)
- {
- /*
- * Incompletely filled block. Possibly the last one.
- */
- if (chn == 0)
- {
- mode[chn] &= ~0x08; /* Disable looping */
- mode[chn] |= 0x20; /* Enable IRQ at the end */
- voices[0].loop_irq_mode = LMODE_PCM_STOP;
- ramp_mode[chn] = 0x03; /* No rollover bit */
- }
- else
- {
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
- 0, is16bits); /* Loop end location */
- mode[chn] &= ~0x08; /* Disable looping */
- }
- }
restore_flags (flags);
}
@@ -2471,6 +2506,8 @@ play_next_pcm_block (void)
cli ();
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]);
restore_flags (flags);
}
@@ -2549,7 +2586,7 @@ gus_transfer_output_block (int dev, unsigned long buf,
*/
dma_active = 1; /* DMA started. There is a unacknowledged buffer */
active_device = GUS_DEV_PCM_DONE;
- if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize))
+ if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize))
{
play_next_pcm_block ();
}
@@ -2567,13 +2604,58 @@ gus_transfer_output_block (int dev, unsigned long buf,
}
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);
}
@@ -2587,7 +2669,7 @@ gus_audio_start_input (int dev, unsigned long buf, int count,
save_flags (flags);
cli ();
- /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
mode = 0xa0; /* DMA IRQ enabled, invert MSB */
@@ -2607,6 +2689,8 @@ 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 */
@@ -2627,6 +2711,7 @@ gus_audio_prepare_for_output (int dev, int bsize, int bcount)
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;
@@ -2636,7 +2721,7 @@ gus_audio_prepare_for_output (int dev, int bsize, int bcount)
pcm_bsize = bsize / gus_audio_channels;
pcm_head = pcm_tail = pcm_qlen = 0;
- pcm_nblk = MAX_PCM_BUFFERS;
+ pcm_nblk = 2; /* MAX_PCM_BUFFERS; */
if ((pcm_bsize * pcm_nblk) > mem_size)
pcm_nblk = mem_size / pcm_bsize;
@@ -2658,56 +2743,6 @@ gus_local_qlen (int dev)
return pcm_qlen;
}
-static void
-gus_copy_from_user (int dev, char *localbuf, int localoffs,
- const char *userbuf, int useroffs, int len)
-{
- if (gus_audio_channels == 1)
- {
- copy_from_user (&localbuf[localoffs], &(userbuf)[useroffs], len);
- }
- else if (gus_audio_bits == 8)
- {
- int in_left = useroffs;
- int in_right = useroffs + 1;
- char *out_left, *out_right;
- int i;
-
- len /= 2;
- localoffs /= 2;
- out_left = localbuf + localoffs;
- out_right = out_left + pcm_bsize;
-
- for (i = 0; i < len; i++)
- {
- get_user (*out_left++, (unsigned char *) &((userbuf)[in_left]));
- in_left += 2;
- get_user (*out_right++, (unsigned char *) &((userbuf)[in_right]));
- in_right += 2;
- }
- }
- else
- {
- int in_left = useroffs;
- int in_right = useroffs + 2;
- short *out_left, *out_right;
- int i;
-
- len /= 4;
- localoffs /= 4;
-
- out_left = ((short *) localbuf) + localoffs;
- out_right = out_left + (pcm_bsize / 2);
-
- for (i = 0; i < len; i++)
- {
- get_user (*out_left++, (unsigned short *) &((userbuf)[in_left]));
- in_left += 4;
- get_user (*out_right++, (unsigned short *) &((userbuf)[in_right]));
- in_right += 4;
- }
- }
-}
static struct audio_driver gus_audio_driver =
{
@@ -2720,7 +2755,7 @@ static struct audio_driver gus_audio_driver =
gus_audio_prepare_for_output,
gus_audio_reset,
gus_local_qlen,
- gus_copy_from_user
+ NULL
};
static void
@@ -3218,7 +3253,10 @@ gus_wave_init (struct address_info *hw_config)
else
{
voice_alloc = &guswave_operations.alloc;
+ if (iw_mode)
+ guswave_operations.id = "IWAVE";
synth_devs[num_synths++] = &guswave_operations;
+ sequencer_init ();
#ifdef CONFIG_SEQUENCER
gus_tmr_install (gus_base + 8);
#endif
@@ -3237,15 +3275,16 @@ gus_wave_init (struct address_info *hw_config)
&gus_audio_driver,
sizeof (struct audio_driver),
NEEDS_RESTART |
- ((dma2 != dma && dma2 != -1) ?
- DMA_DUPLEX : 0),
+ ((!iw_mode && dma2 != dma && dma2 != -1) ?
+ DMA_DUPLEX : 0),
AFMT_U8 | AFMT_S16_LE,
NULL,
dma,
dma2)) < 0)
return;
- audio_devs[gus_devnum]->min_fragment = 9;
+ 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 = num_mixers; /* Next mixer# */
audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
}
@@ -3347,7 +3386,6 @@ do_loop_irq (int voice)
pcm_active = 0; /* Signal to the play_next_pcm_block routine */
case LMODE_PCM:
{
- int flag; /* 0 or 2 */
pcm_qlen--;
pcm_head = (pcm_head + 1) % pcm_nblk;
@@ -3367,20 +3405,11 @@ do_loop_irq (int voice)
}
/*
- * If the queue was full before this interrupt, the DMA transfer was
- * suspended. Let it continue now.
+ * If the queue was full before this interrupt, the DMA transfer was
+ * suspended. Let it continue now.
*/
- if (dma_active)
- {
- if (pcm_qlen == 0)
- flag = 1; /* Underflow */
- else
- flag = 0;
- dma_active = 0;
- }
- else
- flag = 2; /* Just notify the dmabuf.c */
- DMAbuf_outputintr (gus_devnum, flag);
+ if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
+ DMAbuf_outputintr (gus_devnum, 0);
}
break;
@@ -3413,9 +3442,9 @@ do_volume_irq (int voice)
switch (mode)
{
- case VMODE_HALT: /*
- * Decay phase finished
- */
+ case VMODE_HALT: /* Decay phase finished */
+ if (iw_mode)
+ gus_write8 (0x15, 0x02); /* Set voice deactivate bit of SMSI */
restore_flags (flags);
gus_voice_init (voice);
break;
@@ -3523,13 +3552,12 @@ guswave_dma_irq (void)
gus_write8 (0x41, 0); /* Disable GF1 DMA */
if (pcm_qlen < pcm_nblk)
{
- int flag = (1 - dma_active) * 2; /* 0 or 2 */
-
- if (pcm_qlen == 0)
- flag = 1; /* Underrun */
dma_active = 0;
if (gus_busy)
- DMAbuf_outputintr (gus_devnum, flag);
+ {
+ if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
+ DMAbuf_outputintr (gus_devnum, 0);
+ }
}
break;