aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa/gus
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/isa/gus
Linux-2.6.12-rc2v2.6.12-rc2
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!
Diffstat (limited to 'sound/isa/gus')
-rw-r--r--sound/isa/gus/Makefile36
-rw-r--r--sound/isa/gus/gus_dma.c244
-rw-r--r--sound/isa/gus/gus_dram.c103
-rw-r--r--sound/isa/gus/gus_instr.c173
-rw-r--r--sound/isa/gus/gus_io.c531
-rw-r--r--sound/isa/gus/gus_irq.c142
-rw-r--r--sound/isa/gus/gus_main.c514
-rw-r--r--sound/isa/gus/gus_mem.c353
-rw-r--r--sound/isa/gus/gus_mem_proc.c135
-rw-r--r--sound/isa/gus/gus_mixer.c199
-rw-r--r--sound/isa/gus/gus_pcm.c903
-rw-r--r--sound/isa/gus/gus_reset.c413
-rw-r--r--sound/isa/gus/gus_sample.c155
-rw-r--r--sound/isa/gus/gus_simple.c634
-rw-r--r--sound/isa/gus/gus_synth.c329
-rw-r--r--sound/isa/gus/gus_tables.h86
-rw-r--r--sound/isa/gus/gus_timer.c204
-rw-r--r--sound/isa/gus/gus_uart.c257
-rw-r--r--sound/isa/gus/gus_volume.c210
-rw-r--r--sound/isa/gus/gusclassic.c260
-rw-r--r--sound/isa/gus/gusextreme.c374
-rw-r--r--sound/isa/gus/gusmax.c400
-rw-r--r--sound/isa/gus/interwave-stb.c2
-rw-r--r--sound/isa/gus/interwave.c969
24 files changed, 7626 insertions, 0 deletions
diff --git a/sound/isa/gus/Makefile b/sound/isa/gus/Makefile
new file mode 100644
index 000000000000..bae5dbd6c8e5
--- /dev/null
+++ b/sound/isa/gus/Makefile
@@ -0,0 +1,36 @@
1#
2# Makefile for ALSA
3# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-gus-lib-objs := gus_main.o \
7 gus_io.o gus_irq.o gus_timer.o \
8 gus_mem.o gus_mem_proc.o gus_dram.o gus_dma.o gus_volume.o \
9 gus_pcm.o gus_mixer.o \
10 gus_uart.o \
11 gus_reset.o
12snd-gus-synth-objs := gus_synth.o gus_sample.o gus_simple.o gus_instr.o
13
14snd-gusclassic-objs := gusclassic.o
15snd-gusextreme-objs := gusextreme.o
16snd-gusmax-objs := gusmax.o
17snd-interwave-objs := interwave.o
18snd-interwave-stb-objs := interwave-stb.o
19
20#
21# this function returns:
22# "m" - CONFIG_SND_SEQUENCER is m
23# <empty string> - CONFIG_SND_SEQUENCER is undefined
24# otherwise parameter #1 value
25#
26sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
27
28# Toplevel Module Dependency
29obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o
30obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o
31obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o
32obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o
33obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o
34obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-gus-synth.o
35
36obj-m := $(sort $(obj-m))
diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c
new file mode 100644
index 000000000000..de4b56d80b35
--- /dev/null
+++ b/sound/isa/gus/gus_dma.c
@@ -0,0 +1,244 @@
1/*
2 * Routines for GF1 DMA control
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <asm/dma.h>
24#include <linux/slab.h>
25#include <sound/core.h>
26#include <sound/gus.h>
27
28static void snd_gf1_dma_ack(snd_gus_card_t * gus)
29{
30 unsigned long flags;
31
32 spin_lock_irqsave(&gus->reg_lock, flags);
33 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, 0x00);
34 snd_gf1_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL);
35 spin_unlock_irqrestore(&gus->reg_lock, flags);
36}
37
38static void snd_gf1_dma_program(snd_gus_card_t * gus,
39 unsigned int addr,
40 unsigned long buf_addr,
41 unsigned int count,
42 unsigned int cmd)
43{
44 unsigned long flags;
45 unsigned int address;
46 unsigned char dma_cmd;
47 unsigned int address_high;
48
49 // snd_printk("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n", addr, (long) buf, count);
50
51 if (gus->gf1.dma1 > 3) {
52 if (gus->gf1.enh_mode) {
53 address = addr >> 1;
54 } else {
55 if (addr & 0x1f) {
56 snd_printd("snd_gf1_dma_transfer: unaligned address (0x%x)?\n", addr);
57 return;
58 }
59 address = (addr & 0x000c0000) | ((addr & 0x0003ffff) >> 1);
60 }
61 } else {
62 address = addr;
63 }
64
65 dma_cmd = SNDRV_GF1_DMA_ENABLE | (unsigned short) cmd;
66#if 0
67 dma_cmd |= 0x08;
68#endif
69 if (dma_cmd & SNDRV_GF1_DMA_16BIT) {
70 count++;
71 count &= ~1; /* align */
72 }
73 if (gus->gf1.dma1 > 3) {
74 dma_cmd |= SNDRV_GF1_DMA_WIDTH16;
75 count++;
76 count &= ~1; /* align */
77 }
78 snd_gf1_dma_ack(gus);
79 snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE);
80#if 0
81 snd_printk("address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", address << 1, count, dma_cmd);
82#endif
83 spin_lock_irqsave(&gus->reg_lock, flags);
84 if (gus->gf1.enh_mode) {
85 address_high = ((address >> 16) & 0x000000f0) | (address & 0x0000000f);
86 snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4));
87 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH, (unsigned char) address_high);
88 } else
89 snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4));
90 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, dma_cmd);
91 spin_unlock_irqrestore(&gus->reg_lock, flags);
92}
93
94static snd_gf1_dma_block_t *snd_gf1_dma_next_block(snd_gus_card_t * gus)
95{
96 snd_gf1_dma_block_t *block;
97
98 /* PCM block have bigger priority than synthesizer one */
99 if (gus->gf1.dma_data_pcm) {
100 block = gus->gf1.dma_data_pcm;
101 if (gus->gf1.dma_data_pcm_last == block) {
102 gus->gf1.dma_data_pcm =
103 gus->gf1.dma_data_pcm_last = NULL;
104 } else {
105 gus->gf1.dma_data_pcm = block->next;
106 }
107 } else if (gus->gf1.dma_data_synth) {
108 block = gus->gf1.dma_data_synth;
109 if (gus->gf1.dma_data_synth_last == block) {
110 gus->gf1.dma_data_synth =
111 gus->gf1.dma_data_synth_last = NULL;
112 } else {
113 gus->gf1.dma_data_synth = block->next;
114 }
115 } else {
116 block = NULL;
117 }
118 if (block) {
119 gus->gf1.dma_ack = block->ack;
120 gus->gf1.dma_private_data = block->private_data;
121 }
122 return block;
123}
124
125
126static void snd_gf1_dma_interrupt(snd_gus_card_t * gus)
127{
128 snd_gf1_dma_block_t *block;
129
130 snd_gf1_dma_ack(gus);
131 if (gus->gf1.dma_ack)
132 gus->gf1.dma_ack(gus, gus->gf1.dma_private_data);
133 spin_lock(&gus->dma_lock);
134 if (gus->gf1.dma_data_pcm == NULL &&
135 gus->gf1.dma_data_synth == NULL) {
136 gus->gf1.dma_ack = NULL;
137 gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER;
138 spin_unlock(&gus->dma_lock);
139 return;
140 }
141 block = snd_gf1_dma_next_block(gus);
142 spin_unlock(&gus->dma_lock);
143 snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
144 kfree(block);
145#if 0
146 printk("program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", addr, (long) buffer, count, cmd);
147#endif
148}
149
150int snd_gf1_dma_init(snd_gus_card_t * gus)
151{
152 down(&gus->dma_mutex);
153 gus->gf1.dma_shared++;
154 if (gus->gf1.dma_shared > 1) {
155 up(&gus->dma_mutex);
156 return 0;
157 }
158 gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt;
159 gus->gf1.dma_data_pcm =
160 gus->gf1.dma_data_pcm_last =
161 gus->gf1.dma_data_synth =
162 gus->gf1.dma_data_synth_last = NULL;
163 up(&gus->dma_mutex);
164 return 0;
165}
166
167int snd_gf1_dma_done(snd_gus_card_t * gus)
168{
169 snd_gf1_dma_block_t *block;
170
171 down(&gus->dma_mutex);
172 gus->gf1.dma_shared--;
173 if (!gus->gf1.dma_shared) {
174 snd_dma_disable(gus->gf1.dma1);
175 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_DMA_WRITE);
176 snd_gf1_dma_ack(gus);
177 while ((block = gus->gf1.dma_data_pcm)) {
178 gus->gf1.dma_data_pcm = block->next;
179 kfree(block);
180 }
181 while ((block = gus->gf1.dma_data_synth)) {
182 gus->gf1.dma_data_synth = block->next;
183 kfree(block);
184 }
185 gus->gf1.dma_data_pcm_last =
186 gus->gf1.dma_data_synth_last = NULL;
187 }
188 up(&gus->dma_mutex);
189 return 0;
190}
191
192int snd_gf1_dma_transfer_block(snd_gus_card_t * gus,
193 snd_gf1_dma_block_t * __block,
194 int atomic,
195 int synth)
196{
197 unsigned long flags;
198 snd_gf1_dma_block_t *block;
199
200 block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL);
201 if (block == NULL) {
202 snd_printk("gf1: DMA transfer failure; not enough memory\n");
203 return -ENOMEM;
204 }
205 *block = *__block;
206 block->next = NULL;
207#if 0
208 printk("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", block->addr, (long) block->buffer, block->count, block->cmd);
209#endif
210#if 0
211 printk("gus->gf1.dma_data_pcm_last = 0x%lx\n", (long)gus->gf1.dma_data_pcm_last);
212 printk("gus->gf1.dma_data_pcm = 0x%lx\n", (long)gus->gf1.dma_data_pcm);
213#endif
214 spin_lock_irqsave(&gus->dma_lock, flags);
215 if (synth) {
216 if (gus->gf1.dma_data_synth_last) {
217 gus->gf1.dma_data_synth_last->next = block;
218 gus->gf1.dma_data_synth_last = block;
219 } else {
220 gus->gf1.dma_data_synth =
221 gus->gf1.dma_data_synth_last = block;
222 }
223 } else {
224 if (gus->gf1.dma_data_pcm_last) {
225 gus->gf1.dma_data_pcm_last->next = block;
226 gus->gf1.dma_data_pcm_last = block;
227 } else {
228 gus->gf1.dma_data_pcm =
229 gus->gf1.dma_data_pcm_last = block;
230 }
231 }
232 if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) {
233 gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER;
234 block = snd_gf1_dma_next_block(gus);
235 spin_unlock_irqrestore(&gus->dma_lock, flags);
236 if (block == NULL)
237 return 0;
238 snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
239 kfree(block);
240 return 0;
241 }
242 spin_unlock_irqrestore(&gus->dma_lock, flags);
243 return 0;
244}
diff --git a/sound/isa/gus/gus_dram.c b/sound/isa/gus/gus_dram.c
new file mode 100644
index 000000000000..22120b868b5c
--- /dev/null
+++ b/sound/isa/gus/gus_dram.c
@@ -0,0 +1,103 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * DRAM access routines
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/time.h>
24#include <sound/core.h>
25#include <sound/gus.h>
26#include <sound/info.h>
27
28
29static int snd_gus_dram_poke(snd_gus_card_t *gus, char __user *_buffer,
30 unsigned int address, unsigned int size)
31{
32 unsigned long flags;
33 unsigned int size1, size2;
34 char buffer[256], *pbuffer;
35
36 while (size > 0) {
37 size1 = size > sizeof(buffer) ? sizeof(buffer) : size;
38 if (copy_from_user(buffer, _buffer, size1))
39 return -EFAULT;
40 if (gus->interwave) {
41 spin_lock_irqsave(&gus->reg_lock, flags);
42 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
43 snd_gf1_dram_addr(gus, address);
44 outsb(GUSP(gus, DRAM), buffer, size1);
45 spin_unlock_irqrestore(&gus->reg_lock, flags);
46 address += size1;
47 } else {
48 pbuffer = buffer;
49 size2 = size1;
50 while (size2--)
51 snd_gf1_poke(gus, address++, *pbuffer++);
52 }
53 size -= size1;
54 _buffer += size1;
55 }
56 return 0;
57}
58
59
60int snd_gus_dram_write(snd_gus_card_t *gus, char __user *buffer,
61 unsigned int address, unsigned int size)
62{
63 return snd_gus_dram_poke(gus, buffer, address, size);
64}
65
66static int snd_gus_dram_peek(snd_gus_card_t *gus, char __user *_buffer,
67 unsigned int address, unsigned int size,
68 int rom)
69{
70 unsigned long flags;
71 unsigned int size1, size2;
72 char buffer[256], *pbuffer;
73
74 while (size > 0) {
75 size1 = size > sizeof(buffer) ? sizeof(buffer) : size;
76 if (gus->interwave) {
77 spin_lock_irqsave(&gus->reg_lock, flags);
78 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, rom ? 0x03 : 0x01);
79 snd_gf1_dram_addr(gus, address);
80 insb(GUSP(gus, DRAM), buffer, size1);
81 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
82 spin_unlock_irqrestore(&gus->reg_lock, flags);
83 address += size1;
84 } else {
85 pbuffer = buffer;
86 size2 = size1;
87 while (size2--)
88 *pbuffer++ = snd_gf1_peek(gus, address++);
89 }
90 if (copy_to_user(_buffer, buffer, size1))
91 return -EFAULT;
92 size -= size1;
93 _buffer += size1;
94 }
95 return 0;
96}
97
98int snd_gus_dram_read(snd_gus_card_t *gus, char __user *buffer,
99 unsigned int address, unsigned int size,
100 int rom)
101{
102 return snd_gus_dram_peek(gus, buffer, address, size, rom);
103}
diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c
new file mode 100644
index 000000000000..591a9a17feb5
--- /dev/null
+++ b/sound/isa/gus/gus_instr.c
@@ -0,0 +1,173 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Synthesizer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/time.h>
24#include <sound/core.h>
25#include <sound/gus.h>
26
27/*
28 *
29 */
30
31int snd_gus_iwffff_put_sample(void *private_data, iwffff_wave_t *wave,
32 char __user *data, long len, int atomic)
33{
34 snd_gus_card_t *gus = private_data;
35 snd_gf1_mem_block_t *block;
36 int err;
37
38 if (wave->format & IWFFFF_WAVE_ROM)
39 return 0; /* it's probably ok - verify the address? */
40 if (wave->format & IWFFFF_WAVE_STEREO)
41 return -EINVAL; /* not supported */
42 block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
43 SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF,
44 NULL, wave->size,
45 wave->format & IWFFFF_WAVE_16BIT, 1,
46 wave->share_id);
47 if (block == NULL)
48 return -ENOMEM;
49 err = snd_gus_dram_write(gus, data,
50 block->ptr, wave->size);
51 if (err < 0) {
52 snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
53 snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
54 snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
55 return err;
56 }
57 wave->address.memory = block->ptr;
58 return 0;
59}
60
61int snd_gus_iwffff_get_sample(void *private_data, iwffff_wave_t *wave,
62 char __user *data, long len, int atomic)
63{
64 snd_gus_card_t *gus = private_data;
65
66 return snd_gus_dram_read(gus, data, wave->address.memory, wave->size,
67 wave->format & IWFFFF_WAVE_ROM ? 1 : 0);
68}
69
70int snd_gus_iwffff_remove_sample(void *private_data, iwffff_wave_t *wave,
71 int atomic)
72{
73 snd_gus_card_t *gus = private_data;
74
75 if (wave->format & IWFFFF_WAVE_ROM)
76 return 0; /* it's probably ok - verify the address? */
77 return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
78}
79
80/*
81 *
82 */
83
84int snd_gus_gf1_put_sample(void *private_data, gf1_wave_t *wave,
85 char __user *data, long len, int atomic)
86{
87 snd_gus_card_t *gus = private_data;
88 snd_gf1_mem_block_t *block;
89 int err;
90
91 if (wave->format & GF1_WAVE_STEREO)
92 return -EINVAL; /* not supported */
93 block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
94 SNDRV_GF1_MEM_OWNER_WAVE_GF1,
95 NULL, wave->size,
96 wave->format & GF1_WAVE_16BIT, 1,
97 wave->share_id);
98 if (block == NULL)
99 return -ENOMEM;
100 err = snd_gus_dram_write(gus, data,
101 block->ptr, wave->size);
102 if (err < 0) {
103 snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
104 snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
105 snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
106 return err;
107 }
108 wave->address.memory = block->ptr;
109 return 0;
110}
111
112int snd_gus_gf1_get_sample(void *private_data, gf1_wave_t *wave,
113 char __user *data, long len, int atomic)
114{
115 snd_gus_card_t *gus = private_data;
116
117 return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, 0);
118}
119
120int snd_gus_gf1_remove_sample(void *private_data, gf1_wave_t *wave,
121 int atomic)
122{
123 snd_gus_card_t *gus = private_data;
124
125 return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
126}
127
128/*
129 *
130 */
131
132int snd_gus_simple_put_sample(void *private_data, simple_instrument_t *instr,
133 char __user *data, long len, int atomic)
134{
135 snd_gus_card_t *gus = private_data;
136 snd_gf1_mem_block_t *block;
137 int err;
138
139 if (instr->format & SIMPLE_WAVE_STEREO)
140 return -EINVAL; /* not supported */
141 block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
142 SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE,
143 NULL, instr->size,
144 instr->format & SIMPLE_WAVE_16BIT, 1,
145 instr->share_id);
146 if (block == NULL)
147 return -ENOMEM;
148 err = snd_gus_dram_write(gus, data, block->ptr, instr->size);
149 if (err < 0) {
150 snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
151 snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
152 snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
153 return err;
154 }
155 instr->address.memory = block->ptr;
156 return 0;
157}
158
159int snd_gus_simple_get_sample(void *private_data, simple_instrument_t *instr,
160 char __user *data, long len, int atomic)
161{
162 snd_gus_card_t *gus = private_data;
163
164 return snd_gus_dram_read(gus, data, instr->address.memory, instr->size, 0);
165}
166
167int snd_gus_simple_remove_sample(void *private_data, simple_instrument_t *instr,
168 int atomic)
169{
170 snd_gus_card_t *gus = private_data;
171
172 return snd_gf1_mem_free(&gus->gf1.mem_alloc, instr->address.memory);
173}
diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c
new file mode 100644
index 000000000000..f0570f2bf75f
--- /dev/null
+++ b/sound/isa/gus/gus_io.c
@@ -0,0 +1,531 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * I/O routines for GF1/InterWave synthesizer chips
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/delay.h>
24#include <linux/time.h>
25#include <sound/core.h>
26#include <sound/gus.h>
27
28void snd_gf1_delay(snd_gus_card_t * gus)
29{
30 int i;
31
32 for (i = 0; i < 6; i++) {
33 mb();
34 inb(GUSP(gus, DRAM));
35 }
36}
37
38/*
39 * =======================================================================
40 */
41
42/*
43 * ok.. stop of control registers (wave & ramp) need some special things..
44 * big UltraClick (tm) elimination...
45 */
46
47static inline void __snd_gf1_ctrl_stop(snd_gus_card_t * gus, unsigned char reg)
48{
49 unsigned char value;
50
51 outb(reg | 0x80, gus->gf1.reg_regsel);
52 mb();
53 value = inb(gus->gf1.reg_data8);
54 mb();
55 outb(reg, gus->gf1.reg_regsel);
56 mb();
57 outb((value | 0x03) & ~(0x80 | 0x20), gus->gf1.reg_data8);
58 mb();
59}
60
61static inline void __snd_gf1_write8(snd_gus_card_t * gus,
62 unsigned char reg,
63 unsigned char data)
64{
65 outb(reg, gus->gf1.reg_regsel);
66 mb();
67 outb(data, gus->gf1.reg_data8);
68 mb();
69}
70
71static inline unsigned char __snd_gf1_look8(snd_gus_card_t * gus,
72 unsigned char reg)
73{
74 outb(reg, gus->gf1.reg_regsel);
75 mb();
76 return inb(gus->gf1.reg_data8);
77}
78
79static inline void __snd_gf1_write16(snd_gus_card_t * gus,
80 unsigned char reg, unsigned int data)
81{
82 outb(reg, gus->gf1.reg_regsel);
83 mb();
84 outw((unsigned short) data, gus->gf1.reg_data16);
85 mb();
86}
87
88static inline unsigned short __snd_gf1_look16(snd_gus_card_t * gus,
89 unsigned char reg)
90{
91 outb(reg, gus->gf1.reg_regsel);
92 mb();
93 return inw(gus->gf1.reg_data16);
94}
95
96static inline void __snd_gf1_adlib_write(snd_gus_card_t * gus,
97 unsigned char reg, unsigned char data)
98{
99 outb(reg, gus->gf1.reg_timerctrl);
100 inb(gus->gf1.reg_timerctrl);
101 inb(gus->gf1.reg_timerctrl);
102 outb(data, gus->gf1.reg_timerdata);
103 inb(gus->gf1.reg_timerctrl);
104 inb(gus->gf1.reg_timerctrl);
105}
106
107static inline void __snd_gf1_write_addr(snd_gus_card_t * gus, unsigned char reg,
108 unsigned int addr, int w_16bit)
109{
110 if (gus->gf1.enh_mode) {
111 if (w_16bit)
112 addr = ((addr >> 1) & ~0x0000000f) | (addr & 0x0000000f);
113 __snd_gf1_write8(gus, SNDRV_GF1_VB_UPPER_ADDRESS, (unsigned char) ((addr >> 26) & 0x03));
114 } else if (w_16bit)
115 addr = (addr & 0x00c0000f) | ((addr & 0x003ffff0) >> 1);
116 __snd_gf1_write16(gus, reg, (unsigned short) (addr >> 11));
117 __snd_gf1_write16(gus, reg + 1, (unsigned short) (addr << 5));
118}
119
120static inline unsigned int __snd_gf1_read_addr(snd_gus_card_t * gus,
121 unsigned char reg, short w_16bit)
122{
123 unsigned int res;
124
125 res = ((unsigned int) __snd_gf1_look16(gus, reg | 0x80) << 11) & 0xfff800;
126 res |= ((unsigned int) __snd_gf1_look16(gus, (reg + 1) | 0x80) >> 5) & 0x0007ff;
127 if (gus->gf1.enh_mode) {
128 res |= (unsigned int) __snd_gf1_look8(gus, SNDRV_GF1_VB_UPPER_ADDRESS | 0x80) << 26;
129 if (w_16bit)
130 res = ((res << 1) & 0xffffffe0) | (res & 0x0000000f);
131 } else if (w_16bit)
132 res = ((res & 0x001ffff0) << 1) | (res & 0x00c0000f);
133 return res;
134}
135
136
137/*
138 * =======================================================================
139 */
140
141void snd_gf1_ctrl_stop(snd_gus_card_t * gus, unsigned char reg)
142{
143 __snd_gf1_ctrl_stop(gus, reg);
144}
145
146void snd_gf1_write8(snd_gus_card_t * gus,
147 unsigned char reg,
148 unsigned char data)
149{
150 __snd_gf1_write8(gus, reg, data);
151}
152
153unsigned char snd_gf1_look8(snd_gus_card_t * gus, unsigned char reg)
154{
155 return __snd_gf1_look8(gus, reg);
156}
157
158void snd_gf1_write16(snd_gus_card_t * gus,
159 unsigned char reg,
160 unsigned int data)
161{
162 __snd_gf1_write16(gus, reg, data);
163}
164
165unsigned short snd_gf1_look16(snd_gus_card_t * gus, unsigned char reg)
166{
167 return __snd_gf1_look16(gus, reg);
168}
169
170void snd_gf1_adlib_write(snd_gus_card_t * gus,
171 unsigned char reg,
172 unsigned char data)
173{
174 __snd_gf1_adlib_write(gus, reg, data);
175}
176
177void snd_gf1_write_addr(snd_gus_card_t * gus, unsigned char reg,
178 unsigned int addr, short w_16bit)
179{
180 __snd_gf1_write_addr(gus, reg, addr, w_16bit);
181}
182
183unsigned int snd_gf1_read_addr(snd_gus_card_t * gus,
184 unsigned char reg,
185 short w_16bit)
186{
187 return __snd_gf1_read_addr(gus, reg, w_16bit);
188}
189
190/*
191
192 */
193
194void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg)
195{
196 unsigned long flags;
197
198 spin_lock_irqsave(&gus->reg_lock, flags);
199 __snd_gf1_ctrl_stop(gus, reg);
200 spin_unlock_irqrestore(&gus->reg_lock, flags);
201}
202
203void snd_gf1_i_write8(snd_gus_card_t * gus,
204 unsigned char reg,
205 unsigned char data)
206{
207 unsigned long flags;
208
209 spin_lock_irqsave(&gus->reg_lock, flags);
210 __snd_gf1_write8(gus, reg, data);
211 spin_unlock_irqrestore(&gus->reg_lock, flags);
212}
213
214unsigned char snd_gf1_i_look8(snd_gus_card_t * gus, unsigned char reg)
215{
216 unsigned long flags;
217 unsigned char res;
218
219 spin_lock_irqsave(&gus->reg_lock, flags);
220 res = __snd_gf1_look8(gus, reg);
221 spin_unlock_irqrestore(&gus->reg_lock, flags);
222 return res;
223}
224
225void snd_gf1_i_write16(snd_gus_card_t * gus,
226 unsigned char reg,
227 unsigned int data)
228{
229 unsigned long flags;
230
231 spin_lock_irqsave(&gus->reg_lock, flags);
232 __snd_gf1_write16(gus, reg, data);
233 spin_unlock_irqrestore(&gus->reg_lock, flags);
234}
235
236unsigned short snd_gf1_i_look16(snd_gus_card_t * gus, unsigned char reg)
237{
238 unsigned long flags;
239 unsigned short res;
240
241 spin_lock_irqsave(&gus->reg_lock, flags);
242 res = __snd_gf1_look16(gus, reg);
243 spin_unlock_irqrestore(&gus->reg_lock, flags);
244 return res;
245}
246
247void snd_gf1_i_adlib_write(snd_gus_card_t * gus,
248 unsigned char reg,
249 unsigned char data)
250{
251 unsigned long flags;
252
253 spin_lock_irqsave(&gus->reg_lock, flags);
254 __snd_gf1_adlib_write(gus, reg, data);
255 spin_unlock_irqrestore(&gus->reg_lock, flags);
256}
257
258void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg,
259 unsigned int addr, short w_16bit)
260{
261 unsigned long flags;
262
263 spin_lock_irqsave(&gus->reg_lock, flags);
264 __snd_gf1_write_addr(gus, reg, addr, w_16bit);
265 spin_unlock_irqrestore(&gus->reg_lock, flags);
266}
267
268unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
269 unsigned char reg, short w_16bit)
270{
271 unsigned int res;
272 unsigned long flags;
273
274 spin_lock_irqsave(&gus->reg_lock, flags);
275 res = __snd_gf1_read_addr(gus, reg, w_16bit);
276 spin_unlock_irqrestore(&gus->reg_lock, flags);
277 return res;
278}
279
280/*
281
282 */
283
284void snd_gf1_dram_addr(snd_gus_card_t * gus, unsigned int addr)
285{
286 outb(0x43, gus->gf1.reg_regsel);
287 mb();
288 outw((unsigned short) addr, gus->gf1.reg_data16);
289 mb();
290 outb(0x44, gus->gf1.reg_regsel);
291 mb();
292 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
293 mb();
294}
295
296void snd_gf1_poke(snd_gus_card_t * gus, unsigned int addr, unsigned char data)
297{
298 unsigned long flags;
299
300 spin_lock_irqsave(&gus->reg_lock, flags);
301 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
302 mb();
303 outw((unsigned short) addr, gus->gf1.reg_data16);
304 mb();
305 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
306 mb();
307 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
308 mb();
309 outb(data, gus->gf1.reg_dram);
310 spin_unlock_irqrestore(&gus->reg_lock, flags);
311}
312
313unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr)
314{
315 unsigned long flags;
316 unsigned char res;
317
318 spin_lock_irqsave(&gus->reg_lock, flags);
319 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
320 mb();
321 outw((unsigned short) addr, gus->gf1.reg_data16);
322 mb();
323 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
324 mb();
325 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
326 mb();
327 res = inb(gus->gf1.reg_dram);
328 spin_unlock_irqrestore(&gus->reg_lock, flags);
329 return res;
330}
331
332void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data)
333{
334 unsigned long flags;
335
336#ifdef CONFIG_SND_DEBUG
337 if (!gus->interwave)
338 snd_printk("snd_gf1_pokew - GF1!!!\n");
339#endif
340 spin_lock_irqsave(&gus->reg_lock, flags);
341 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
342 mb();
343 outw((unsigned short) addr, gus->gf1.reg_data16);
344 mb();
345 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
346 mb();
347 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
348 mb();
349 outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
350 mb();
351 outw(data, gus->gf1.reg_data16);
352 spin_unlock_irqrestore(&gus->reg_lock, flags);
353}
354
355unsigned short snd_gf1_peekw(snd_gus_card_t * gus, unsigned int addr)
356{
357 unsigned long flags;
358 unsigned short res;
359
360#ifdef CONFIG_SND_DEBUG
361 if (!gus->interwave)
362 snd_printk("snd_gf1_peekw - GF1!!!\n");
363#endif
364 spin_lock_irqsave(&gus->reg_lock, flags);
365 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
366 mb();
367 outw((unsigned short) addr, gus->gf1.reg_data16);
368 mb();
369 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
370 mb();
371 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
372 mb();
373 outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
374 mb();
375 res = inw(gus->gf1.reg_data16);
376 spin_unlock_irqrestore(&gus->reg_lock, flags);
377 return res;
378}
379
380void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr,
381 unsigned short value, unsigned int count)
382{
383 unsigned long port;
384 unsigned long flags;
385
386#ifdef CONFIG_SND_DEBUG
387 if (!gus->interwave)
388 snd_printk("snd_gf1_dram_setmem - GF1!!!\n");
389#endif
390 addr &= ~1;
391 count >>= 1;
392 port = GUSP(gus, GF1DATALOW);
393 spin_lock_irqsave(&gus->reg_lock, flags);
394 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
395 mb();
396 outw((unsigned short) addr, gus->gf1.reg_data16);
397 mb();
398 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
399 mb();
400 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
401 mb();
402 outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
403 while (count--)
404 outw(value, port);
405 spin_unlock_irqrestore(&gus->reg_lock, flags);
406}
407
408/*
409
410 */
411
412void snd_gf1_select_active_voices(snd_gus_card_t * gus)
413{
414 unsigned short voices;
415
416 static unsigned short voices_tbl[32 - 14 + 1] =
417 {
418 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
419 25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
420 };
421
422 voices = gus->gf1.active_voices;
423 if (voices > 32)
424 voices = 32;
425 if (voices < 14)
426 voices = 14;
427 if (gus->gf1.enh_mode)
428 voices = 32;
429 gus->gf1.active_voices = voices;
430 gus->gf1.playback_freq =
431 gus->gf1.enh_mode ? 44100 : voices_tbl[voices - 14];
432 if (!gus->gf1.enh_mode) {
433 snd_gf1_i_write8(gus, SNDRV_GF1_GB_ACTIVE_VOICES, 0xc0 | (voices - 1));
434 udelay(100);
435 }
436}
437
438#ifdef CONFIG_SND_DEBUG
439
440void snd_gf1_print_voice_registers(snd_gus_card_t * gus)
441{
442 unsigned char mode;
443 int voice, ctrl;
444
445 voice = gus->gf1.active_voice;
446 printk(" -%i- GF1 voice ctrl, ramp ctrl = 0x%x, 0x%x\n", voice, ctrl = snd_gf1_i_read8(gus, 0), snd_gf1_i_read8(gus, 0x0d));
447 printk(" -%i- GF1 frequency = 0x%x\n", voice, snd_gf1_i_read16(gus, 1));
448 printk(" -%i- GF1 loop start, end = 0x%x (0x%x), 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 2, ctrl & 4), snd_gf1_i_read_addr(gus, 2, (ctrl & 4) ^ 4), snd_gf1_i_read_addr(gus, 4, ctrl & 4), snd_gf1_i_read_addr(gus, 4, (ctrl & 4) ^ 4));
449 printk(" -%i- GF1 ramp start, end, rate = 0x%x, 0x%x, 0x%x\n", voice, snd_gf1_i_read8(gus, 7), snd_gf1_i_read8(gus, 8), snd_gf1_i_read8(gus, 6));
450 printk(" -%i- GF1 volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 9));
451 printk(" -%i- GF1 position = 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 0x0a, ctrl & 4), snd_gf1_i_read_addr(gus, 0x0a, (ctrl & 4) ^ 4));
452 if (gus->interwave && snd_gf1_i_read8(gus, 0x19) & 0x01) { /* enhanced mode */
453 mode = snd_gf1_i_read8(gus, 0x15);
454 printk(" -%i- GFA1 mode = 0x%x\n", voice, mode);
455 if (mode & 0x01) { /* Effect processor */
456 printk(" -%i- GFA1 effect address = 0x%x\n", voice, snd_gf1_i_read_addr(gus, 0x11, ctrl & 4));
457 printk(" -%i- GFA1 effect volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x16));
458 printk(" -%i- GFA1 effect volume final = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x1d));
459 printk(" -%i- GFA1 effect acumulator = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x14));
460 }
461 if (mode & 0x20) {
462 printk(" -%i- GFA1 left offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x13), snd_gf1_i_read16(gus, 0x13) >> 4);
463 printk(" -%i- GFA1 left offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1c), snd_gf1_i_read16(gus, 0x1c) >> 4);
464 printk(" -%i- GFA1 right offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x0c), snd_gf1_i_read16(gus, 0x0c) >> 4);
465 printk(" -%i- GFA1 right offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1b), snd_gf1_i_read16(gus, 0x1b) >> 4);
466 } else
467 printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c));
468 } else
469 printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c));
470}
471
472void snd_gf1_print_global_registers(snd_gus_card_t * gus)
473{
474 unsigned char global_mode = 0x00;
475
476 printk(" -G- GF1 active voices = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ACTIVE_VOICES));
477 if (gus->interwave) {
478 global_mode = snd_gf1_i_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE);
479 printk(" -G- GF1 global mode = 0x%x\n", global_mode);
480 }
481 if (global_mode & 0x02) /* LFO enabled? */
482 printk(" -G- GF1 LFO base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_LFO_BASE));
483 printk(" -G- GF1 voices IRQ read = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VOICES_IRQ_READ));
484 printk(" -G- GF1 DRAM DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL));
485 printk(" -G- GF1 DRAM DMA high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW));
486 printk(" -G- GF1 DRAM IO high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_IO_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_IO_LOW));
487 if (!gus->interwave)
488 printk(" -G- GF1 record DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL));
489 printk(" -G- GF1 DRAM IO 16 = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_DRAM_IO16));
490 if (gus->gf1.enh_mode) {
491 printk(" -G- GFA1 memory config = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG));
492 printk(" -G- GFA1 memory control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MEMORY_CONTROL));
493 printk(" -G- GFA1 FIFO record base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR));
494 printk(" -G- GFA1 FIFO playback base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR));
495 printk(" -G- GFA1 interleave control = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_INTERLEAVE));
496 }
497}
498
499void snd_gf1_print_setup_registers(snd_gus_card_t * gus)
500{
501 printk(" -S- mix control = 0x%x\n", inb(GUSP(gus, MIXCNTRLREG)));
502 printk(" -S- IRQ status = 0x%x\n", inb(GUSP(gus, IRQSTAT)));
503 printk(" -S- timer control = 0x%x\n", inb(GUSP(gus, TIMERCNTRL)));
504 printk(" -S- timer data = 0x%x\n", inb(GUSP(gus, TIMERDATA)));
505 printk(" -S- status read = 0x%x\n", inb(GUSP(gus, REGCNTRLS)));
506 printk(" -S- Sound Blaster control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL));
507 printk(" -S- AdLib timer 1/2 = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1), snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2));
508 printk(" -S- reset = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET));
509 if (gus->interwave) {
510 printk(" -S- compatibility = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_COMPATIBILITY));
511 printk(" -S- decode control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DECODE_CONTROL));
512 printk(" -S- version number = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER));
513 printk(" -S- MPU-401 emul. control A/B = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A), snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B));
514 printk(" -S- emulation IRQ = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_EMULATION_IRQ));
515 }
516}
517
518void snd_gf1_peek_print_block(snd_gus_card_t * gus, unsigned int addr, int count, int w_16bit)
519{
520 if (!w_16bit) {
521 while (count-- > 0)
522 printk(count > 0 ? "%02x:" : "%02x", snd_gf1_peek(gus, addr++));
523 } else {
524 while (count-- > 0) {
525 printk(count > 0 ? "%04x:" : "%04x", snd_gf1_peek(gus, addr) | (snd_gf1_peek(gus, addr + 1) << 8));
526 addr += 2;
527 }
528 }
529}
530
531#endif
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
new file mode 100644
index 000000000000..1e2a15eb8106
--- /dev/null
+++ b/sound/isa/gus/gus_irq.c
@@ -0,0 +1,142 @@
1/*
2 * Routine for IRQ handling from GF1/InterWave chip
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <sound/core.h>
24#include <sound/info.h>
25#include <sound/gus.h>
26
27#ifdef CONFIG_SND_DEBUG
28#define STAT_ADD(x) ((x)++)
29#else
30#define STAT_ADD(x) while (0) { ; }
31#endif
32
33irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
34{
35 snd_gus_card_t * gus = dev_id;
36 unsigned char status;
37 int loop = 100;
38 int handled = 0;
39
40__again:
41 status = inb(gus->gf1.reg_irqstat);
42 if (status == 0)
43 return IRQ_RETVAL(handled);
44 handled = 1;
45 // snd_printk("IRQ: status = 0x%x\n", status);
46 if (status & 0x02) {
47 STAT_ADD(gus->gf1.interrupt_stat_midi_in);
48 gus->gf1.interrupt_handler_midi_in(gus);
49 }
50 if (status & 0x01) {
51 STAT_ADD(gus->gf1.interrupt_stat_midi_out);
52 gus->gf1.interrupt_handler_midi_out(gus);
53 }
54 if (status & (0x20 | 0x40)) {
55 unsigned int already, _current_;
56 unsigned char voice_status, voice;
57 snd_gus_voice_t *pvoice;
58
59 already = 0;
60 while (((voice_status = snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ)) & 0xc0) != 0xc0) {
61 voice = voice_status & 0x1f;
62 _current_ = 1 << voice;
63 if (already & _current_)
64 continue; /* multi request */
65 already |= _current_; /* mark request */
66#if 0
67 printk("voice = %i, voice_status = 0x%x, voice_verify = %i\n", voice, voice_status, inb(GUSP(gus, GF1PAGE)));
68#endif
69 pvoice = &gus->gf1.voices[voice];
70 if (pvoice->use) {
71 if (!(voice_status & 0x80)) { /* voice position IRQ */
72 STAT_ADD(pvoice->interrupt_stat_wave);
73 pvoice->handler_wave(gus, pvoice);
74 }
75 if (!(voice_status & 0x40)) { /* volume ramp IRQ */
76 STAT_ADD(pvoice->interrupt_stat_volume);
77 pvoice->handler_volume(gus, pvoice);
78 }
79 } else {
80 STAT_ADD(gus->gf1.interrupt_stat_voice_lost);
81 snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
82 snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
83 }
84 }
85 }
86 if (status & 0x04) {
87 STAT_ADD(gus->gf1.interrupt_stat_timer1);
88 gus->gf1.interrupt_handler_timer1(gus);
89 }
90 if (status & 0x08) {
91 STAT_ADD(gus->gf1.interrupt_stat_timer2);
92 gus->gf1.interrupt_handler_timer2(gus);
93 }
94 if (status & 0x80) {
95 if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) {
96 STAT_ADD(gus->gf1.interrupt_stat_dma_write);
97 gus->gf1.interrupt_handler_dma_write(gus);
98 }
99 if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) {
100 STAT_ADD(gus->gf1.interrupt_stat_dma_read);
101 gus->gf1.interrupt_handler_dma_read(gus);
102 }
103 }
104 if (--loop > 0)
105 goto __again;
106 return IRQ_NONE;
107}
108
109#ifdef CONFIG_SND_DEBUG
110static void snd_gus_irq_info_read(snd_info_entry_t *entry,
111 snd_info_buffer_t * buffer)
112{
113 snd_gus_card_t *gus;
114 snd_gus_voice_t *pvoice;
115 int idx;
116
117 gus = entry->private_data;
118 snd_iprintf(buffer, "midi out = %u\n", gus->gf1.interrupt_stat_midi_out);
119 snd_iprintf(buffer, "midi in = %u\n", gus->gf1.interrupt_stat_midi_in);
120 snd_iprintf(buffer, "timer1 = %u\n", gus->gf1.interrupt_stat_timer1);
121 snd_iprintf(buffer, "timer2 = %u\n", gus->gf1.interrupt_stat_timer2);
122 snd_iprintf(buffer, "dma write = %u\n", gus->gf1.interrupt_stat_dma_write);
123 snd_iprintf(buffer, "dma read = %u\n", gus->gf1.interrupt_stat_dma_read);
124 snd_iprintf(buffer, "voice lost = %u\n", gus->gf1.interrupt_stat_voice_lost);
125 for (idx = 0; idx < 32; idx++) {
126 pvoice = &gus->gf1.voices[idx];
127 snd_iprintf(buffer, "voice %i: wave = %u, volume = %u\n",
128 idx,
129 pvoice->interrupt_stat_wave,
130 pvoice->interrupt_stat_volume);
131 }
132}
133
134void snd_gus_irq_profile_init(snd_gus_card_t *gus)
135{
136 snd_info_entry_t *entry;
137
138 if (! snd_card_proc_new(gus->card, "gusirq", &entry))
139 snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read);
140}
141
142#endif
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
new file mode 100644
index 000000000000..73f81c14f768
--- /dev/null
+++ b/sound/isa/gus/gus_main.c
@@ -0,0 +1,514 @@
1/*
2 * Routines for Gravis UltraSound soundcards
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/init.h>
24#include <linux/interrupt.h>
25#include <linux/delay.h>
26#include <linux/slab.h>
27#include <linux/ioport.h>
28#include <sound/core.h>
29#include <sound/gus.h>
30#include <sound/control.h>
31
32#include <asm/dma.h>
33
34MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
35MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards");
36MODULE_LICENSE("GPL");
37
38static int snd_gus_init_dma_irq(snd_gus_card_t * gus, int latches);
39
40int snd_gus_use_inc(snd_gus_card_t * gus)
41{
42 if (!try_module_get(gus->card->module))
43 return 0;
44 return 1;
45}
46
47void snd_gus_use_dec(snd_gus_card_t * gus)
48{
49 module_put(gus->card->module);
50}
51
52static int snd_gus_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
53{
54 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
55 uinfo->count = 1;
56 uinfo->value.integer.min = 0;
57 uinfo->value.integer.max = 31;
58 return 0;
59}
60
61static int snd_gus_joystick_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
62{
63 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
64
65 ucontrol->value.integer.value[0] = gus->joystick_dac & 31;
66 return 0;
67}
68
69static int snd_gus_joystick_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
70{
71 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
72 unsigned long flags;
73 int change;
74 unsigned char nval;
75
76 nval = ucontrol->value.integer.value[0] & 31;
77 spin_lock_irqsave(&gus->reg_lock, flags);
78 change = gus->joystick_dac != nval;
79 gus->joystick_dac = nval;
80 snd_gf1_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac);
81 spin_unlock_irqrestore(&gus->reg_lock, flags);
82 return change;
83}
84
85static snd_kcontrol_new_t snd_gus_joystick_control = {
86 .iface = SNDRV_CTL_ELEM_IFACE_CARD,
87 .name = "Joystick Speed",
88 .info = snd_gus_joystick_info,
89 .get = snd_gus_joystick_get,
90 .put = snd_gus_joystick_put
91};
92
93static void snd_gus_init_control(snd_gus_card_t *gus)
94{
95 if (!gus->ace_flag)
96 snd_ctl_add(gus->card, snd_ctl_new1(&snd_gus_joystick_control, gus));
97}
98
99/*
100 *
101 */
102
103static int snd_gus_free(snd_gus_card_t *gus)
104{
105 if (gus->gf1.res_port2 == NULL)
106 goto __hw_end;
107#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
108 if (gus->seq_dev) {
109 snd_device_free(gus->card, gus->seq_dev);
110 gus->seq_dev = NULL;
111 }
112#endif
113 snd_gf1_stop(gus);
114 snd_gus_init_dma_irq(gus, 0);
115 __hw_end:
116 if (gus->gf1.res_port1) {
117 release_resource(gus->gf1.res_port1);
118 kfree_nocheck(gus->gf1.res_port1);
119 }
120 if (gus->gf1.res_port2) {
121 release_resource(gus->gf1.res_port2);
122 kfree_nocheck(gus->gf1.res_port2);
123 }
124 if (gus->gf1.irq >= 0)
125 free_irq(gus->gf1.irq, (void *) gus);
126 if (gus->gf1.dma1 >= 0) {
127 disable_dma(gus->gf1.dma1);
128 free_dma(gus->gf1.dma1);
129 }
130 if (!gus->equal_dma && gus->gf1.dma2 >= 0) {
131 disable_dma(gus->gf1.dma2);
132 free_dma(gus->gf1.dma2);
133 }
134 kfree(gus);
135 return 0;
136}
137
138static int snd_gus_dev_free(snd_device_t *device)
139{
140 snd_gus_card_t *gus = device->device_data;
141 return snd_gus_free(gus);
142}
143
144int snd_gus_create(snd_card_t * card,
145 unsigned long port,
146 int irq, int dma1, int dma2,
147 int timer_dev,
148 int voices,
149 int pcm_channels,
150 int effect,
151 snd_gus_card_t **rgus)
152{
153 snd_gus_card_t *gus;
154 int err;
155 static snd_device_ops_t ops = {
156 .dev_free = snd_gus_dev_free,
157 };
158
159 *rgus = NULL;
160 gus = kcalloc(1, sizeof(*gus), GFP_KERNEL);
161 if (gus == NULL)
162 return -ENOMEM;
163 gus->gf1.irq = -1;
164 gus->gf1.dma1 = -1;
165 gus->gf1.dma2 = -1;
166 gus->card = card;
167 gus->gf1.port = port;
168 /* fill register variables for speedup */
169 gus->gf1.reg_page = GUSP(gus, GF1PAGE);
170 gus->gf1.reg_regsel = GUSP(gus, GF1REGSEL);
171 gus->gf1.reg_data8 = GUSP(gus, GF1DATAHIGH);
172 gus->gf1.reg_data16 = GUSP(gus, GF1DATALOW);
173 gus->gf1.reg_irqstat = GUSP(gus, IRQSTAT);
174 gus->gf1.reg_dram = GUSP(gus, DRAM);
175 gus->gf1.reg_timerctrl = GUSP(gus, TIMERCNTRL);
176 gus->gf1.reg_timerdata = GUSP(gus, TIMERDATA);
177 /* allocate resources */
178 if ((gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)")) == NULL) {
179 snd_printk(KERN_ERR "gus: can't grab SB port 0x%lx\n", port);
180 snd_gus_free(gus);
181 return -EBUSY;
182 }
183 if ((gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)")) == NULL) {
184 snd_printk(KERN_ERR "gus: can't grab synth port 0x%lx\n", port + 0x100);
185 snd_gus_free(gus);
186 return -EBUSY;
187 }
188 if (irq >= 0 && request_irq(irq, snd_gus_interrupt, SA_INTERRUPT, "GUS GF1", (void *) gus)) {
189 snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq);
190 snd_gus_free(gus);
191 return -EBUSY;
192 }
193 gus->gf1.irq = irq;
194 if (request_dma(dma1, "GUS - 1")) {
195 snd_printk(KERN_ERR "gus: can't grab DMA1 %d\n", dma1);
196 snd_gus_free(gus);
197 return -EBUSY;
198 }
199 gus->gf1.dma1 = dma1;
200 if (dma2 >= 0 && dma1 != dma2) {
201 if (request_dma(dma2, "GUS - 2")) {
202 snd_printk(KERN_ERR "gus: can't grab DMA2 %d\n", dma2);
203 snd_gus_free(gus);
204 return -EBUSY;
205 }
206 gus->gf1.dma2 = dma2;
207 } else {
208 gus->gf1.dma2 = gus->gf1.dma1;
209 gus->equal_dma = 1;
210 }
211 gus->timer_dev = timer_dev;
212 if (voices < 14)
213 voices = 14;
214 if (voices > 32)
215 voices = 32;
216 if (pcm_channels < 0)
217 pcm_channels = 0;
218 if (pcm_channels > 8)
219 pcm_channels = 8;
220 pcm_channels++;
221 pcm_channels &= ~1;
222 gus->gf1.effect = effect ? 1 : 0;
223 gus->gf1.active_voices = voices;
224 gus->gf1.pcm_channels = pcm_channels;
225 gus->gf1.volume_ramp = 25;
226 gus->gf1.smooth_pan = 1;
227 spin_lock_init(&gus->reg_lock);
228 spin_lock_init(&gus->voice_alloc);
229 spin_lock_init(&gus->active_voice_lock);
230 spin_lock_init(&gus->event_lock);
231 spin_lock_init(&gus->dma_lock);
232 spin_lock_init(&gus->pcm_volume_level_lock);
233 spin_lock_init(&gus->uart_cmd_lock);
234 init_MUTEX(&gus->dma_mutex);
235 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops)) < 0) {
236 snd_gus_free(gus);
237 return err;
238 }
239 *rgus = gus;
240 return 0;
241}
242
243/*
244 * Memory detection routine for plain GF1 soundcards
245 */
246
247static int snd_gus_detect_memory(snd_gus_card_t * gus)
248{
249 int l, idx, local;
250 unsigned char d;
251
252 snd_gf1_poke(gus, 0L, 0xaa);
253 snd_gf1_poke(gus, 1L, 0x55);
254 if (snd_gf1_peek(gus, 0L) != 0xaa || snd_gf1_peek(gus, 1L) != 0x55) {
255 snd_printk("plain GF1 card at 0x%lx without onboard DRAM?\n", gus->gf1.port);
256 return -ENOMEM;
257 }
258 for (idx = 1, d = 0xab; idx < 4; idx++, d++) {
259 local = idx << 18;
260 snd_gf1_poke(gus, local, d);
261 snd_gf1_poke(gus, local + 1, d + 1);
262 if (snd_gf1_peek(gus, local) != d ||
263 snd_gf1_peek(gus, local + 1) != d + 1 ||
264 snd_gf1_peek(gus, 0L) != 0xaa)
265 break;
266 }
267#if 1
268 gus->gf1.memory = idx << 18;
269#else
270 gus->gf1.memory = 256 * 1024;
271#endif
272 for (l = 0, local = gus->gf1.memory; l < 4; l++, local -= 256 * 1024) {
273 gus->gf1.mem_alloc.banks_8[l].address =
274 gus->gf1.mem_alloc.banks_8[l].size = 0;
275 gus->gf1.mem_alloc.banks_16[l].address = l << 18;
276 gus->gf1.mem_alloc.banks_16[l].size = local > 0 ? 256 * 1024 : 0;
277 }
278 gus->gf1.mem_alloc.banks_8[0].size = gus->gf1.memory;
279 return 0; /* some memory were detected */
280}
281
282static int snd_gus_init_dma_irq(snd_gus_card_t * gus, int latches)
283{
284 snd_card_t *card;
285 unsigned long flags;
286 int irq, dma1, dma2;
287 static unsigned char irqs[16] =
288 {0, 0, 1, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
289 static unsigned char dmas[8] =
290 {6, 1, 0, 2, 0, 3, 4, 5};
291
292 snd_assert(gus != NULL, return -EINVAL);
293 card = gus->card;
294 snd_assert(card != NULL, return -EINVAL);
295
296 gus->mix_cntrl_reg &= 0xf8;
297 gus->mix_cntrl_reg |= 0x01; /* disable MIC, LINE IN, enable LINE OUT */
298 if (gus->codec_flag || gus->ess_flag) {
299 gus->mix_cntrl_reg &= ~1; /* enable LINE IN */
300 gus->mix_cntrl_reg |= 4; /* enable MIC */
301 }
302 dma1 = gus->gf1.dma1;
303 dma1 = dma1 < 0 ? -dma1 : dma1;
304 dma1 = dmas[dma1 & 7];
305 dma2 = gus->gf1.dma2;
306 dma2 = dma2 < 0 ? -dma2 : dma2;
307 dma2 = dmas[dma2 & 7];
308#if 0
309 printk("dma1 = %i, dma2 = %i\n", gus->gf1.dma1, gus->gf1.dma2);
310#endif
311 dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);
312
313 if ((dma1 & 7) == 0 || (dma2 & 7) == 0) {
314 snd_printk("Error! DMA isn't defined.\n");
315 return -EINVAL;
316 }
317 irq = gus->gf1.irq;
318 irq = irq < 0 ? -irq : irq;
319 irq = irqs[irq & 0x0f];
320 if (irq == 0) {
321 snd_printk("Error! IRQ isn't defined.\n");
322 return -EINVAL;
323 }
324 irq |= 0x40;
325#if 0
326 card->mixer.mix_ctrl_reg |= 0x10;
327#endif
328
329 spin_lock_irqsave(&gus->reg_lock, flags);
330 outb(5, GUSP(gus, REGCNTRLS));
331 outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
332 outb(0x00, GUSP(gus, IRQDMACNTRLREG));
333 outb(0, GUSP(gus, REGCNTRLS));
334 spin_unlock_irqrestore(&gus->reg_lock, flags);
335
336 udelay(100);
337
338 spin_lock_irqsave(&gus->reg_lock, flags);
339 outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
340 outb(dma1, GUSP(gus, IRQDMACNTRLREG));
341 if (latches) {
342 outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
343 outb(irq, GUSP(gus, IRQDMACNTRLREG));
344 }
345 spin_unlock_irqrestore(&gus->reg_lock, flags);
346
347 udelay(100);
348
349 spin_lock_irqsave(&gus->reg_lock, flags);
350 outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
351 outb(dma1, GUSP(gus, IRQDMACNTRLREG));
352 if (latches) {
353 outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
354 outb(irq, GUSP(gus, IRQDMACNTRLREG));
355 }
356 spin_unlock_irqrestore(&gus->reg_lock, flags);
357
358 snd_gf1_delay(gus);
359
360 if (latches)
361 gus->mix_cntrl_reg |= 0x08; /* enable latches */
362 else
363 gus->mix_cntrl_reg &= ~0x08; /* disable latches */
364 spin_lock_irqsave(&gus->reg_lock, flags);
365 outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
366 outb(0, GUSP(gus, GF1PAGE));
367 spin_unlock_irqrestore(&gus->reg_lock, flags);
368
369 return 0;
370}
371
372static int snd_gus_check_version(snd_gus_card_t * gus)
373{
374 unsigned long flags;
375 unsigned char val, rev;
376 snd_card_t *card;
377
378 card = gus->card;
379 spin_lock_irqsave(&gus->reg_lock, flags);
380 outb(0x20, GUSP(gus, REGCNTRLS));
381 val = inb(GUSP(gus, REGCNTRLS));
382 rev = inb(GUSP(gus, BOARDVERSION));
383 spin_unlock_irqrestore(&gus->reg_lock, flags);
384 snd_printdd("GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev);
385 strcpy(card->driver, "GUS");
386 strcpy(card->longname, "Gravis UltraSound Classic (2.4)");
387 if ((val != 255 && (val & 0x06)) || (rev >= 5 && rev != 255)) {
388 if (rev >= 5 && rev <= 9) {
389 gus->ics_flag = 1;
390 if (rev == 5)
391 gus->ics_flipped = 1;
392 card->longname[27] = '3';
393 card->longname[29] = rev == 5 ? '5' : '7';
394 }
395 if (rev >= 10 && rev != 255) {
396 if (rev >= 10 && rev <= 11) {
397 strcpy(card->driver, "GUS MAX");
398 strcpy(card->longname, "Gravis UltraSound MAX");
399 gus->max_flag = 1;
400 } else if (rev == 0x30) {
401 strcpy(card->driver, "GUS ACE");
402 strcpy(card->longname, "Gravis UltraSound Ace");
403 gus->ace_flag = 1;
404 } else if (rev == 0x50) {
405 strcpy(card->driver, "GUS Extreme");
406 strcpy(card->longname, "Gravis UltraSound Extreme");
407 gus->ess_flag = 1;
408 } else {
409 snd_printk("unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val);
410 snd_printk(" please - report to <perex@suse.cz>\n");
411 }
412 }
413 }
414 strcpy(card->shortname, card->longname);
415 gus->uart_enable = 1; /* standard GUSes doesn't have midi uart trouble */
416 snd_gus_init_control(gus);
417 return 0;
418}
419
420static void snd_gus_seq_dev_free(snd_seq_device_t *seq_dev)
421{
422 snd_gus_card_t *gus = seq_dev->private_data;
423 gus->seq_dev = NULL;
424}
425
426int snd_gus_initialize(snd_gus_card_t *gus)
427{
428 int err;
429
430 if (!gus->interwave) {
431 if ((err = snd_gus_check_version(gus)) < 0) {
432 snd_printk("version check failed\n");
433 return err;
434 }
435 if ((err = snd_gus_detect_memory(gus)) < 0)
436 return err;
437 }
438 if ((err = snd_gus_init_dma_irq(gus, 1)) < 0)
439 return err;
440#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
441 if (snd_seq_device_new(gus->card, 1, SNDRV_SEQ_DEV_ID_GUS,
442 sizeof(snd_gus_card_t*), &gus->seq_dev) >= 0) {
443 strcpy(gus->seq_dev->name, "GUS");
444 *(snd_gus_card_t**)SNDRV_SEQ_DEVICE_ARGPTR(gus->seq_dev) = gus;
445 gus->seq_dev->private_data = gus;
446 gus->seq_dev->private_free = snd_gus_seq_dev_free;
447 }
448#endif
449 snd_gf1_start(gus);
450 gus->initialized = 1;
451 return 0;
452}
453
454 /* gus_io.c */
455EXPORT_SYMBOL(snd_gf1_delay);
456EXPORT_SYMBOL(snd_gf1_write8);
457EXPORT_SYMBOL(snd_gf1_look8);
458EXPORT_SYMBOL(snd_gf1_write16);
459EXPORT_SYMBOL(snd_gf1_look16);
460EXPORT_SYMBOL(snd_gf1_i_write8);
461EXPORT_SYMBOL(snd_gf1_i_look8);
462EXPORT_SYMBOL(snd_gf1_i_write16);
463EXPORT_SYMBOL(snd_gf1_i_look16);
464EXPORT_SYMBOL(snd_gf1_dram_addr);
465EXPORT_SYMBOL(snd_gf1_write_addr);
466EXPORT_SYMBOL(snd_gf1_poke);
467EXPORT_SYMBOL(snd_gf1_peek);
468 /* gus_reset.c */
469EXPORT_SYMBOL(snd_gf1_alloc_voice);
470EXPORT_SYMBOL(snd_gf1_free_voice);
471EXPORT_SYMBOL(snd_gf1_ctrl_stop);
472EXPORT_SYMBOL(snd_gf1_stop_voice);
473EXPORT_SYMBOL(snd_gf1_start);
474EXPORT_SYMBOL(snd_gf1_stop);
475 /* gus_mixer.c */
476EXPORT_SYMBOL(snd_gf1_new_mixer);
477 /* gus_pcm.c */
478EXPORT_SYMBOL(snd_gf1_pcm_new);
479 /* gus.c */
480EXPORT_SYMBOL(snd_gus_use_inc);
481EXPORT_SYMBOL(snd_gus_use_dec);
482EXPORT_SYMBOL(snd_gus_create);
483EXPORT_SYMBOL(snd_gus_initialize);
484 /* gus_irq.c */
485EXPORT_SYMBOL(snd_gus_interrupt);
486 /* gus_uart.c */
487EXPORT_SYMBOL(snd_gf1_rawmidi_new);
488 /* gus_dram.c */
489EXPORT_SYMBOL(snd_gus_dram_write);
490EXPORT_SYMBOL(snd_gus_dram_read);
491 /* gus_volume.c */
492EXPORT_SYMBOL(snd_gf1_lvol_to_gvol_raw);
493EXPORT_SYMBOL(snd_gf1_translate_freq);
494 /* gus_mem.c */
495EXPORT_SYMBOL(snd_gf1_mem_alloc);
496EXPORT_SYMBOL(snd_gf1_mem_xfree);
497EXPORT_SYMBOL(snd_gf1_mem_free);
498EXPORT_SYMBOL(snd_gf1_mem_lock);
499
500/*
501 * INIT part
502 */
503
504static int __init alsa_gus_init(void)
505{
506 return 0;
507}
508
509static void __exit alsa_gus_exit(void)
510{
511}
512
513module_init(alsa_gus_init)
514module_exit(alsa_gus_exit)
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
new file mode 100644
index 000000000000..bfc2b91001d5
--- /dev/null
+++ b/sound/isa/gus/gus_mem.c
@@ -0,0 +1,353 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * GUS's memory allocation routines / bottom layer
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/slab.h>
24#include <sound/core.h>
25#include <sound/gus.h>
26#include <sound/info.h>
27
28#ifdef CONFIG_SND_DEBUG
29static void snd_gf1_mem_info_read(snd_info_entry_t *entry,
30 snd_info_buffer_t * buffer);
31#endif
32
33void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup)
34{
35 if (!xup) {
36 down(&alloc->memory_mutex);
37 } else {
38 up(&alloc->memory_mutex);
39 }
40}
41
42snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc,
43 snd_gf1_mem_block_t * block)
44{
45 snd_gf1_mem_block_t *pblock, *nblock;
46
47 nblock = (snd_gf1_mem_block_t *) kmalloc(sizeof(snd_gf1_mem_block_t), GFP_KERNEL);
48 if (nblock == NULL)
49 return NULL;
50 *nblock = *block;
51 pblock = alloc->first;
52 while (pblock) {
53 if (pblock->ptr > nblock->ptr) {
54 nblock->prev = pblock->prev;
55 nblock->next = pblock;
56 pblock->prev = nblock;
57 if (pblock == alloc->first)
58 alloc->first = nblock;
59 else
60 nblock->prev->next = nblock;
61 up(&alloc->memory_mutex);
62 return NULL;
63 }
64 pblock = pblock->next;
65 }
66 nblock->next = NULL;
67 if (alloc->last == NULL) {
68 nblock->prev = NULL;
69 alloc->first = alloc->last = nblock;
70 } else {
71 nblock->prev = alloc->last;
72 alloc->last->next = nblock;
73 alloc->last = nblock;
74 }
75 return nblock;
76}
77
78int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block)
79{
80 if (block->share) { /* ok.. shared block */
81 block->share--;
82 up(&alloc->memory_mutex);
83 return 0;
84 }
85 if (alloc->first == block) {
86 alloc->first = block->next;
87 if (block->next)
88 block->next->prev = NULL;
89 } else {
90 block->prev->next = block->next;
91 if (block->next)
92 block->next->prev = block->prev;
93 }
94 if (alloc->last == block) {
95 alloc->last = block->prev;
96 if (block->prev)
97 block->prev->next = NULL;
98 } else {
99 block->next->prev = block->prev;
100 if (block->prev)
101 block->prev->next = block->next;
102 }
103 kfree(block->name);
104 kfree(block);
105 return 0;
106}
107
108snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc,
109 unsigned int address)
110{
111 snd_gf1_mem_block_t *block;
112
113 for (block = alloc->first; block; block = block->next) {
114 if (block->ptr == address) {
115 return block;
116 }
117 }
118 return NULL;
119}
120
121snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc,
122 unsigned int *share_id)
123{
124 snd_gf1_mem_block_t *block;
125
126 if (!share_id[0] && !share_id[1] &&
127 !share_id[2] && !share_id[3])
128 return NULL;
129 for (block = alloc->first; block; block = block->next)
130 if (!memcmp(share_id, block->share_id, sizeof(share_id)))
131 return block;
132 return NULL;
133}
134
135static int snd_gf1_mem_find(snd_gf1_mem_t * alloc,
136 snd_gf1_mem_block_t * block,
137 unsigned int size, int w_16, int align)
138{
139 snd_gf1_bank_info_t *info = w_16 ? alloc->banks_16 : alloc->banks_8;
140 unsigned int idx, boundary;
141 int size1;
142 snd_gf1_mem_block_t *pblock;
143 unsigned int ptr1, ptr2;
144
145 align--;
146 if (w_16 && align < 1)
147 align = 1;
148 block->flags = w_16 ? SNDRV_GF1_MEM_BLOCK_16BIT : 0;
149 block->owner = SNDRV_GF1_MEM_OWNER_DRIVER;
150 block->share = 0;
151 block->share_id[0] = block->share_id[1] =
152 block->share_id[2] = block->share_id[3] = 0;
153 block->name = NULL;
154 block->prev = block->next = NULL;
155 for (pblock = alloc->first, idx = 0; pblock; pblock = pblock->next) {
156 while (pblock->ptr >= (boundary = info[idx].address + info[idx].size))
157 idx++;
158 while (pblock->ptr + pblock->size >= (boundary = info[idx].address + info[idx].size))
159 idx++;
160 ptr2 = boundary;
161 if (pblock->next) {
162 if (pblock->ptr + pblock->size == pblock->next->ptr)
163 continue;
164 if (pblock->next->ptr < boundary)
165 ptr2 = pblock->next->ptr;
166 }
167 ptr1 = (pblock->ptr + pblock->size + align) & ~align;
168 if (ptr1 >= ptr2)
169 continue;
170 size1 = ptr2 - ptr1;
171 if ((int)size <= size1) {
172 block->ptr = ptr1;
173 block->size = size;
174 return 0;
175 }
176 }
177 while (++idx < 4) {
178 if (size <= info[idx].size) {
179 /* I assume that bank address is already aligned.. */
180 block->ptr = info[idx].address;
181 block->size = size;
182 return 0;
183 }
184 }
185 return -ENOMEM;
186}
187
188snd_gf1_mem_block_t *snd_gf1_mem_alloc(snd_gf1_mem_t * alloc, int owner,
189 char *name, int size, int w_16, int align,
190 unsigned int *share_id)
191{
192 snd_gf1_mem_block_t block, *nblock;
193
194 snd_gf1_mem_lock(alloc, 0);
195 if (share_id != NULL) {
196 nblock = snd_gf1_mem_share(alloc, share_id);
197 if (nblock != NULL) {
198 if (size != (int)nblock->size) {
199 /* TODO: remove in the future */
200 snd_printk("snd_gf1_mem_alloc - share: sizes differ\n");
201 goto __std;
202 }
203 nblock->share++;
204 snd_gf1_mem_lock(alloc, 1);
205 return NULL;
206 }
207 }
208 __std:
209 if (snd_gf1_mem_find(alloc, &block, size, w_16, align) < 0) {
210 snd_gf1_mem_lock(alloc, 1);
211 return NULL;
212 }
213 if (share_id != NULL)
214 memcpy(&block.share_id, share_id, sizeof(block.share_id));
215 block.owner = owner;
216 block.name = snd_kmalloc_strdup(name, GFP_KERNEL);
217 nblock = snd_gf1_mem_xalloc(alloc, &block);
218 snd_gf1_mem_lock(alloc, 1);
219 return nblock;
220}
221
222int snd_gf1_mem_free(snd_gf1_mem_t * alloc, unsigned int address)
223{
224 int result;
225 snd_gf1_mem_block_t *block;
226
227 snd_gf1_mem_lock(alloc, 0);
228 if ((block = snd_gf1_mem_look(alloc, address)) != NULL) {
229 result = snd_gf1_mem_xfree(alloc, block);
230 snd_gf1_mem_lock(alloc, 1);
231 return result;
232 }
233 snd_gf1_mem_lock(alloc, 1);
234 return -EINVAL;
235}
236
237int snd_gf1_mem_init(snd_gus_card_t * gus)
238{
239 snd_gf1_mem_t *alloc;
240 snd_gf1_mem_block_t block;
241#ifdef CONFIG_SND_DEBUG
242 snd_info_entry_t *entry;
243#endif
244
245 alloc = &gus->gf1.mem_alloc;
246 init_MUTEX(&alloc->memory_mutex);
247 alloc->first = alloc->last = NULL;
248 if (!gus->gf1.memory)
249 return 0;
250
251 memset(&block, 0, sizeof(block));
252 block.owner = SNDRV_GF1_MEM_OWNER_DRIVER;
253 if (gus->gf1.enh_mode) {
254 block.ptr = 0;
255 block.size = 1024;
256 block.name = snd_kmalloc_strdup("InterWave LFOs", GFP_KERNEL);
257 if (snd_gf1_mem_xalloc(alloc, &block) == NULL)
258 return -ENOMEM;
259 }
260 block.ptr = gus->gf1.default_voice_address;
261 block.size = 4;
262 block.name = snd_kmalloc_strdup("Voice default (NULL's)", GFP_KERNEL);
263 if (snd_gf1_mem_xalloc(alloc, &block) == NULL)
264 return -ENOMEM;
265#ifdef CONFIG_SND_DEBUG
266 if (! snd_card_proc_new(gus->card, "gusmem", &entry)) {
267 snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read);
268 entry->c.text.read_size = 256 * 1024;
269 }
270#endif
271 return 0;
272}
273
274int snd_gf1_mem_done(snd_gus_card_t * gus)
275{
276 snd_gf1_mem_t *alloc;
277 snd_gf1_mem_block_t *block, *nblock;
278
279 alloc = &gus->gf1.mem_alloc;
280 block = alloc->first;
281 while (block) {
282 nblock = block->next;
283 snd_gf1_mem_xfree(alloc, block);
284 block = nblock;
285 }
286 return 0;
287}
288
289#ifdef CONFIG_SND_DEBUG
290static void snd_gf1_mem_info_read(snd_info_entry_t *entry,
291 snd_info_buffer_t * buffer)
292{
293 snd_gus_card_t *gus;
294 snd_gf1_mem_t *alloc;
295 snd_gf1_mem_block_t *block;
296 unsigned int total, used;
297 int i;
298
299 gus = entry->private_data;
300 alloc = &gus->gf1.mem_alloc;
301 down(&alloc->memory_mutex);
302 snd_iprintf(buffer, "8-bit banks : \n ");
303 for (i = 0; i < 4; i++)
304 snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_8[i].address, alloc->banks_8[i].size >> 10, i + 1 < 4 ? "," : "");
305 snd_iprintf(buffer, "\n"
306 "16-bit banks : \n ");
307 for (i = total = 0; i < 4; i++) {
308 snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_16[i].address, alloc->banks_16[i].size >> 10, i + 1 < 4 ? "," : "");
309 total += alloc->banks_16[i].size;
310 }
311 snd_iprintf(buffer, "\n");
312 used = 0;
313 for (block = alloc->first, i = 0; block; block = block->next, i++) {
314 used += block->size;
315 snd_iprintf(buffer, "Block %i at 0x%lx onboard 0x%x size %i (0x%x):\n", i, (long) block, block->ptr, block->size, block->size);
316 if (block->share ||
317 block->share_id[0] || block->share_id[1] ||
318 block->share_id[2] || block->share_id[3])
319 snd_iprintf(buffer, " Share : %i [id0 0x%x] [id1 0x%x] [id2 0x%x] [id3 0x%x]\n",
320 block->share,
321 block->share_id[0], block->share_id[1],
322 block->share_id[2], block->share_id[3]);
323 snd_iprintf(buffer, " Flags :%s\n",
324 block->flags & SNDRV_GF1_MEM_BLOCK_16BIT ? " 16-bit" : "");
325 snd_iprintf(buffer, " Owner : ");
326 switch (block->owner) {
327 case SNDRV_GF1_MEM_OWNER_DRIVER:
328 snd_iprintf(buffer, "driver - %s\n", block->name);
329 break;
330 case SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE:
331 snd_iprintf(buffer, "SIMPLE wave\n");
332 break;
333 case SNDRV_GF1_MEM_OWNER_WAVE_GF1:
334 snd_iprintf(buffer, "GF1 wave\n");
335 break;
336 case SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF:
337 snd_iprintf(buffer, "IWFFFF wave\n");
338 break;
339 default:
340 snd_iprintf(buffer, "unknown\n");
341 }
342 }
343 snd_iprintf(buffer, " Total: memory = %i, used = %i, free = %i\n",
344 total, used, total - used);
345 up(&alloc->memory_mutex);
346#if 0
347 ultra_iprintf(buffer, " Verify: free = %i, max 8-bit block = %i, max 16-bit block = %i\n",
348 ultra_memory_free_size(card, &card->gf1.mem_alloc),
349 ultra_memory_free_block(card, &card->gf1.mem_alloc, 0),
350 ultra_memory_free_block(card, &card->gf1.mem_alloc, 1));
351#endif
352}
353#endif
diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c
new file mode 100644
index 000000000000..886763f12132
--- /dev/null
+++ b/sound/isa/gus/gus_mem_proc.c
@@ -0,0 +1,135 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * GUS's memory access via proc filesystem
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/slab.h>
24#include <sound/core.h>
25#include <sound/gus.h>
26#include <sound/info.h>
27
28typedef struct gus_proc_private {
29 int rom; /* data are in ROM */
30 unsigned int address;
31 unsigned int size;
32 snd_gus_card_t * gus;
33} gus_proc_private_t;
34
35static long snd_gf1_mem_proc_dump(snd_info_entry_t *entry, void *file_private_data,
36 struct file *file, char __user *buf,
37 unsigned long count, unsigned long pos)
38{
39 long size;
40 gus_proc_private_t *priv = entry->private_data;
41 snd_gus_card_t *gus = priv->gus;
42 int err;
43
44 size = count;
45 if (pos + size > priv->size)
46 size = (long)priv->size - pos;
47 if (size > 0) {
48 if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
49 return err;
50 return size;
51 }
52 return 0;
53}
54
55static long long snd_gf1_mem_proc_llseek(snd_info_entry_t *entry,
56 void *private_file_data,
57 struct file *file,
58 long long offset,
59 int orig)
60{
61 gus_proc_private_t *priv = entry->private_data;
62
63 switch (orig) {
64 case 0: /* SEEK_SET */
65 file->f_pos = offset;
66 break;
67 case 1: /* SEEK_CUR */
68 file->f_pos += offset;
69 break;
70 case 2: /* SEEK_END, offset is negative */
71 file->f_pos = priv->size + offset;
72 break;
73 default:
74 return -EINVAL;
75 }
76 if (file->f_pos > priv->size)
77 file->f_pos = priv->size;
78 return file->f_pos;
79}
80
81static void snd_gf1_mem_proc_free(snd_info_entry_t *entry)
82{
83 gus_proc_private_t *priv = entry->private_data;
84 kfree(priv);
85}
86
87static struct snd_info_entry_ops snd_gf1_mem_proc_ops = {
88 .read = snd_gf1_mem_proc_dump,
89 .llseek = snd_gf1_mem_proc_llseek,
90};
91
92int snd_gf1_mem_proc_init(snd_gus_card_t * gus)
93{
94 int idx;
95 char name[16];
96 gus_proc_private_t *priv;
97 snd_info_entry_t *entry;
98
99 for (idx = 0; idx < 4; idx++) {
100 if (gus->gf1.mem_alloc.banks_8[idx].size > 0) {
101 priv = kcalloc(1, sizeof(*priv), GFP_KERNEL);
102 if (priv == NULL)
103 return -ENOMEM;
104 priv->gus = gus;
105 sprintf(name, "gus-ram-%i", idx);
106 if (! snd_card_proc_new(gus->card, name, &entry)) {
107 entry->content = SNDRV_INFO_CONTENT_DATA;
108 entry->private_data = priv;
109 entry->private_free = snd_gf1_mem_proc_free;
110 entry->c.ops = &snd_gf1_mem_proc_ops;
111 priv->address = gus->gf1.mem_alloc.banks_8[idx].address;
112 priv->size = entry->size = gus->gf1.mem_alloc.banks_8[idx].size;
113 }
114 }
115 }
116 for (idx = 0; idx < 4; idx++) {
117 if (gus->gf1.rom_present & (1 << idx)) {
118 priv = kcalloc(1, sizeof(*priv), GFP_KERNEL);
119 if (priv == NULL)
120 return -ENOMEM;
121 priv->rom = 1;
122 priv->gus = gus;
123 sprintf(name, "gus-rom-%i", idx);
124 if (! snd_card_proc_new(gus->card, name, &entry)) {
125 entry->content = SNDRV_INFO_CONTENT_DATA;
126 entry->private_data = priv;
127 entry->private_free = snd_gf1_mem_proc_free;
128 entry->c.ops = &snd_gf1_mem_proc_ops;
129 priv->address = idx * 4096 * 1024;
130 priv->size = entry->size = gus->gf1.rom_memory;
131 }
132 }
133 }
134 return 0;
135}
diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c
new file mode 100644
index 000000000000..a051094d510e
--- /dev/null
+++ b/sound/isa/gus/gus_mixer.c
@@ -0,0 +1,199 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for control of ICS 2101 chip and "mixer" in GF1 chip
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/time.h>
24#include <linux/wait.h>
25#include <sound/core.h>
26#include <sound/control.h>
27#include <sound/gus.h>
28
29/*
30 *
31 */
32
33#define GF1_SINGLE(xname, xindex, shift, invert) \
34{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
35 .info = snd_gf1_info_single, \
36 .get = snd_gf1_get_single, .put = snd_gf1_put_single, \
37 .private_value = shift | (invert << 8) }
38
39static int snd_gf1_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
40{
41 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
42 uinfo->count = 1;
43 uinfo->value.integer.min = 0;
44 uinfo->value.integer.max = 1;
45 return 0;
46}
47
48static int snd_gf1_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
49{
50 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
51 int shift = kcontrol->private_value & 0xff;
52 int invert = (kcontrol->private_value >> 8) & 1;
53
54 ucontrol->value.integer.value[0] = (gus->mix_cntrl_reg >> shift) & 1;
55 if (invert)
56 ucontrol->value.integer.value[0] ^= 1;
57 return 0;
58}
59
60static int snd_gf1_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
61{
62 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
63 unsigned long flags;
64 int shift = kcontrol->private_value & 0xff;
65 int invert = (kcontrol->private_value >> 8) & 1;
66 int change;
67 unsigned char oval, nval;
68
69 nval = ucontrol->value.integer.value[0] & 1;
70 if (invert)
71 nval ^= 1;
72 nval <<= shift;
73 spin_lock_irqsave(&gus->reg_lock, flags);
74 oval = gus->mix_cntrl_reg;
75 nval = (oval & ~(1 << shift)) | nval;
76 change = nval != oval;
77 outb(gus->mix_cntrl_reg = nval, GUSP(gus, MIXCNTRLREG));
78 outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));
79 spin_unlock_irqrestore(&gus->reg_lock, flags);
80 return change;
81}
82
83#define ICS_DOUBLE(xname, xindex, addr) \
84{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
85 .info = snd_ics_info_double, \
86 .get = snd_ics_get_double, .put = snd_ics_put_double, \
87 .private_value = addr }
88
89static int snd_ics_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
90{
91 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
92 uinfo->count = 2;
93 uinfo->value.integer.min = 0;
94 uinfo->value.integer.max = 127;
95 return 0;
96}
97
98static int snd_ics_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
99{
100 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
101 unsigned long flags;
102 int addr = kcontrol->private_value & 0xff;
103 unsigned char left, right;
104
105 spin_lock_irqsave(&gus->reg_lock, flags);
106 left = gus->gf1.ics_regs[addr][0];
107 right = gus->gf1.ics_regs[addr][1];
108 spin_unlock_irqrestore(&gus->reg_lock, flags);
109 ucontrol->value.integer.value[0] = left & 127;
110 ucontrol->value.integer.value[1] = right & 127;
111 return 0;
112}
113
114static int snd_ics_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
115{
116 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
117 unsigned long flags;
118 int addr = kcontrol->private_value & 0xff;
119 int change;
120 unsigned char val1, val2, oval1, oval2, tmp;
121
122 val1 = ucontrol->value.integer.value[0] & 127;
123 val2 = ucontrol->value.integer.value[1] & 127;
124 spin_lock_irqsave(&gus->reg_lock, flags);
125 oval1 = gus->gf1.ics_regs[addr][0];
126 oval2 = gus->gf1.ics_regs[addr][1];
127 change = val1 != oval1 || val2 != oval2;
128 gus->gf1.ics_regs[addr][0] = val1;
129 gus->gf1.ics_regs[addr][1] = val2;
130 if (gus->ics_flag && gus->ics_flipped &&
131 (addr == SNDRV_ICS_GF1_DEV || addr == SNDRV_ICS_MASTER_DEV)) {
132 tmp = val1;
133 val1 = val2;
134 val2 = tmp;
135 }
136 addr <<= 3;
137 outb(addr | 0, GUSP(gus, MIXCNTRLPORT));
138 outb(1, GUSP(gus, MIXDATAPORT));
139 outb(addr | 2, GUSP(gus, MIXCNTRLPORT));
140 outb((unsigned char) val1, GUSP(gus, MIXDATAPORT));
141 outb(addr | 1, GUSP(gus, MIXCNTRLPORT));
142 outb(2, GUSP(gus, MIXDATAPORT));
143 outb(addr | 3, GUSP(gus, MIXCNTRLPORT));
144 outb((unsigned char) val2, GUSP(gus, MIXDATAPORT));
145 spin_unlock_irqrestore(&gus->reg_lock, flags);
146 return change;
147}
148
149static snd_kcontrol_new_t snd_gf1_controls[] = {
150GF1_SINGLE("Master Playback Switch", 0, 1, 1),
151GF1_SINGLE("Line Switch", 0, 0, 1),
152GF1_SINGLE("Mic Switch", 0, 2, 0)
153};
154
155static snd_kcontrol_new_t snd_ics_controls[] = {
156GF1_SINGLE("Master Playback Switch", 0, 1, 1),
157ICS_DOUBLE("Master Playback Volume", 0, SNDRV_ICS_MASTER_DEV),
158ICS_DOUBLE("Synth Playback Volume", 0, SNDRV_ICS_GF1_DEV),
159GF1_SINGLE("Line Switch", 0, 0, 1),
160ICS_DOUBLE("Line Playback Volume", 0, SNDRV_ICS_LINE_DEV),
161GF1_SINGLE("Mic Switch", 0, 2, 0),
162ICS_DOUBLE("Mic Playback Volume", 0, SNDRV_ICS_MIC_DEV),
163ICS_DOUBLE("CD Playback Volume", 0, SNDRV_ICS_CD_DEV)
164};
165
166int snd_gf1_new_mixer(snd_gus_card_t * gus)
167{
168 snd_card_t *card;
169 unsigned int idx, max;
170 int err;
171
172 snd_assert(gus != NULL, return -EINVAL);
173 card = gus->card;
174 snd_assert(card != NULL, return -EINVAL);
175
176 if (gus->ics_flag)
177 snd_component_add(card, "ICS2101");
178 if (card->mixername[0] == '\0') {
179 strcpy(card->mixername, gus->ics_flag ? "GF1,ICS2101" : "GF1");
180 } else {
181 if (gus->ics_flag)
182 strcat(card->mixername, ",ICS2101");
183 strcat(card->mixername, ",GF1");
184 }
185
186 if (!gus->ics_flag) {
187 max = gus->ess_flag ? 1 : ARRAY_SIZE(snd_gf1_controls);
188 for (idx = 0; idx < max; idx++) {
189 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_gf1_controls[idx], gus))) < 0)
190 return err;
191 }
192 } else {
193 for (idx = 0; idx < ARRAY_SIZE(snd_ics_controls); idx++) {
194 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ics_controls[idx], gus))) < 0)
195 return err;
196 }
197 }
198 return 0;
199}
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
new file mode 100644
index 000000000000..8995ad9c516d
--- /dev/null
+++ b/sound/isa/gus/gus_pcm.c
@@ -0,0 +1,903 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for control of GF1 chip (PCM things)
4 *
5 * InterWave chips supports interleaved DMA, but this feature isn't used in
6 * this code.
7 *
8 * This code emulates autoinit DMA transfer for playback, recording by GF1
9 * chip doesn't support autoinit DMA.
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 */
27
28#include <sound/driver.h>
29#include <asm/dma.h>
30#include <linux/slab.h>
31#include <sound/core.h>
32#include <sound/control.h>
33#include <sound/gus.h>
34#include <sound/pcm_params.h>
35#include "gus_tables.h"
36
37/* maximum rate */
38
39#define SNDRV_GF1_PCM_RATE 48000
40
41#define SNDRV_GF1_PCM_PFLG_NONE 0
42#define SNDRV_GF1_PCM_PFLG_ACTIVE (1<<0)
43#define SNDRV_GF1_PCM_PFLG_NEUTRAL (2<<0)
44
45typedef struct {
46 snd_gus_card_t * gus;
47 snd_pcm_substream_t * substream;
48 spinlock_t lock;
49 unsigned int voices;
50 snd_gus_voice_t *pvoices[2];
51 unsigned int memory;
52 unsigned short flags;
53 unsigned char voice_ctrl, ramp_ctrl;
54 unsigned int bpos;
55 unsigned int blocks;
56 unsigned int block_size;
57 unsigned int dma_size;
58 wait_queue_head_t sleep;
59 atomic_t dma_count;
60 int final_volume;
61} gus_pcm_private_t;
62
63static int snd_gf1_pcm_use_dma = 1;
64
65static void snd_gf1_pcm_block_change_ack(snd_gus_card_t * gus, void *private_data)
66{
67 gus_pcm_private_t *pcmp = private_data;
68
69 if (pcmp) {
70 atomic_dec(&pcmp->dma_count);
71 wake_up(&pcmp->sleep);
72 }
73}
74
75static int snd_gf1_pcm_block_change(snd_pcm_substream_t * substream,
76 unsigned int offset,
77 unsigned int addr,
78 unsigned int count)
79{
80 snd_gf1_dma_block_t block;
81 snd_pcm_runtime_t *runtime = substream->runtime;
82 gus_pcm_private_t *pcmp = runtime->private_data;
83
84 count += offset & 31;
85 offset &= ~31;
86 // snd_printk("block change - offset = 0x%x, count = 0x%x\n", offset, count);
87 memset(&block, 0, sizeof(block));
88 block.cmd = SNDRV_GF1_DMA_IRQ;
89 if (snd_pcm_format_unsigned(runtime->format))
90 block.cmd |= SNDRV_GF1_DMA_UNSIGNED;
91 if (snd_pcm_format_width(runtime->format) == 16)
92 block.cmd |= SNDRV_GF1_DMA_16BIT;
93 block.addr = addr & ~31;
94 block.buffer = runtime->dma_area + offset;
95 block.buf_addr = runtime->dma_addr + offset;
96 block.count = count;
97 block.private_data = pcmp;
98 block.ack = snd_gf1_pcm_block_change_ack;
99 if (!snd_gf1_dma_transfer_block(pcmp->gus, &block, 0, 0))
100 atomic_inc(&pcmp->dma_count);
101 return 0;
102}
103
104static void snd_gf1_pcm_trigger_up(snd_pcm_substream_t * substream)
105{
106 snd_pcm_runtime_t *runtime = substream->runtime;
107 gus_pcm_private_t *pcmp = runtime->private_data;
108 snd_gus_card_t * gus = pcmp->gus;
109 unsigned long flags;
110 unsigned char voice_ctrl, ramp_ctrl;
111 unsigned short rate;
112 unsigned int curr, begin, end;
113 unsigned short vol;
114 unsigned char pan;
115 unsigned int voice;
116
117 if (substream == NULL)
118 return;
119 spin_lock_irqsave(&pcmp->lock, flags);
120 if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {
121 spin_unlock_irqrestore(&pcmp->lock, flags);
122 return;
123 }
124 pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE;
125 pcmp->final_volume = 0;
126 spin_unlock_irqrestore(&pcmp->lock, flags);
127 rate = snd_gf1_translate_freq(gus, runtime->rate << 4);
128 /* enable WAVE IRQ */
129 voice_ctrl = snd_pcm_format_width(runtime->format) == 16 ? 0x24 : 0x20;
130 /* enable RAMP IRQ + rollover */
131 ramp_ctrl = 0x24;
132 if (pcmp->blocks == 1) {
133 voice_ctrl |= 0x08; /* loop enable */
134 ramp_ctrl &= ~0x04; /* disable rollover */
135 }
136 for (voice = 0; voice < pcmp->voices; voice++) {
137 begin = pcmp->memory + voice * (pcmp->dma_size / runtime->channels);
138 curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;
139 end = curr + (pcmp->block_size / runtime->channels);
140 end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;
141 // snd_printk("init: curr=0x%x, begin=0x%x, end=0x%x, ctrl=0x%x, ramp=0x%x, rate=0x%x\n", curr, begin, end, voice_ctrl, ramp_ctrl, rate);
142 pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;
143 vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
144 spin_lock_irqsave(&gus->reg_lock, flags);
145 snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);
146 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, pan);
147 snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, rate);
148 snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, begin << 4, voice_ctrl & 4);
149 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4);
150 snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, curr << 4, voice_ctrl & 4);
151 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME << 4);
152 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, 0x2f);
153 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, SNDRV_GF1_MIN_OFFSET);
154 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, vol >> 8);
155 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
156 if (!gus->gf1.enh_mode) {
157 snd_gf1_delay(gus);
158 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
159 }
160 spin_unlock_irqrestore(&gus->reg_lock, flags);
161 }
162 spin_lock_irqsave(&gus->reg_lock, flags);
163 for (voice = 0; voice < pcmp->voices; voice++) {
164 snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);
165 if (gus->gf1.enh_mode)
166 snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, 0x00); /* deactivate voice */
167 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);
168 voice_ctrl &= ~0x20;
169 }
170 voice_ctrl |= 0x20;
171 if (!gus->gf1.enh_mode) {
172 snd_gf1_delay(gus);
173 for (voice = 0; voice < pcmp->voices; voice++) {
174 snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);
175 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);
176 voice_ctrl &= ~0x20; /* disable IRQ for next voice */
177 }
178 }
179 spin_unlock_irqrestore(&gus->reg_lock, flags);
180}
181
182static void snd_gf1_pcm_interrupt_wave(snd_gus_card_t * gus, snd_gus_voice_t *pvoice)
183{
184 gus_pcm_private_t * pcmp;
185 snd_pcm_runtime_t * runtime;
186 unsigned char voice_ctrl, ramp_ctrl;
187 unsigned int idx;
188 unsigned int end, step;
189
190 if (!pvoice->private_data) {
191 snd_printd("snd_gf1_pcm: unknown wave irq?\n");
192 snd_gf1_smart_stop_voice(gus, pvoice->number);
193 return;
194 }
195 pcmp = pvoice->private_data;
196 if (pcmp == NULL) {
197 snd_printd("snd_gf1_pcm: unknown wave irq?\n");
198 snd_gf1_smart_stop_voice(gus, pvoice->number);
199 return;
200 }
201 gus = pcmp->gus;
202 runtime = pcmp->substream->runtime;
203
204 spin_lock(&gus->reg_lock);
205 snd_gf1_select_voice(gus, pvoice->number);
206 voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & ~0x8b;
207 ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;
208#if 0
209 snd_gf1_select_voice(gus, pvoice->number);
210 printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
211 snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);
212 printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
213 snd_gf1_select_voice(gus, pvoice->number);
214#endif
215 pcmp->bpos++;
216 pcmp->bpos %= pcmp->blocks;
217 if (pcmp->bpos + 1 >= pcmp->blocks) { /* last block? */
218 voice_ctrl |= 0x08; /* enable loop */
219 } else {
220 ramp_ctrl |= 0x04; /* enable rollover */
221 }
222 end = pcmp->memory + (((pcmp->bpos + 1) * pcmp->block_size) / runtime->channels);
223 end -= voice_ctrl & 4 ? 2 : 1;
224 step = pcmp->dma_size / runtime->channels;
225 voice_ctrl |= 0x20;
226 if (!pcmp->final_volume) {
227 ramp_ctrl |= 0x20;
228 ramp_ctrl &= ~0x03;
229 }
230 for (idx = 0; idx < pcmp->voices; idx++, end += step) {
231 snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number);
232 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4);
233 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);
234 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
235 voice_ctrl &= ~0x20;
236 }
237 if (!gus->gf1.enh_mode) {
238 snd_gf1_delay(gus);
239 voice_ctrl |= 0x20;
240 for (idx = 0; idx < pcmp->voices; idx++) {
241 snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number);
242 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);
243 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
244 voice_ctrl &= ~0x20;
245 }
246 }
247 spin_unlock(&gus->reg_lock);
248
249 snd_pcm_period_elapsed(pcmp->substream);
250#if 0
251 if ((runtime->flags & SNDRV_PCM_FLG_MMAP) &&
252 *runtime->state == SNDRV_PCM_STATE_RUNNING) {
253 end = pcmp->bpos * pcmp->block_size;
254 if (runtime->channels > 1) {
255 snd_gf1_pcm_block_change(pcmp->substream, end, pcmp->memory + (end / 2), pcmp->block_size / 2);
256 snd_gf1_pcm_block_change(pcmp->substream, end + (pcmp->block_size / 2), pcmp->memory + (pcmp->dma_size / 2) + (end / 2), pcmp->block_size / 2);
257 } else {
258 snd_gf1_pcm_block_change(pcmp->substream, end, pcmp->memory + end, pcmp->block_size);
259 }
260 }
261#endif
262}
263
264static void snd_gf1_pcm_interrupt_volume(snd_gus_card_t * gus, snd_gus_voice_t * pvoice)
265{
266 unsigned short vol;
267 int cvoice;
268 gus_pcm_private_t *pcmp = pvoice->private_data;
269
270 /* stop ramp, but leave rollover bit untouched */
271 spin_lock(&gus->reg_lock);
272 snd_gf1_select_voice(gus, pvoice->number);
273 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
274 spin_unlock(&gus->reg_lock);
275 if (pcmp == NULL)
276 return;
277 /* are we active? */
278 if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))
279 return;
280 /* load real volume - better precision */
281 cvoice = pcmp->pvoices[0] == pvoice ? 0 : 1;
282 if (pcmp->substream == NULL)
283 return;
284 vol = !cvoice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
285 spin_lock(&gus->reg_lock);
286 snd_gf1_select_voice(gus, pvoice->number);
287 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);
288 pcmp->final_volume = 1;
289 spin_unlock(&gus->reg_lock);
290}
291
292static void snd_gf1_pcm_volume_change(snd_gus_card_t * gus)
293{
294}
295
296static int snd_gf1_pcm_poke_block(snd_gus_card_t *gus, unsigned char *buf,
297 unsigned int pos, unsigned int count,
298 int w16, int invert)
299{
300 unsigned int len;
301 unsigned long flags;
302
303 // printk("poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n", (int)buf, pos, count, gus->gf1.port);
304 while (count > 0) {
305 len = count;
306 if (len > 512) /* limit, to allow IRQ */
307 len = 512;
308 count -= len;
309 if (gus->interwave) {
310 spin_lock_irqsave(&gus->reg_lock, flags);
311 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01 | (invert ? 0x08 : 0x00));
312 snd_gf1_dram_addr(gus, pos);
313 if (w16) {
314 outb(SNDRV_GF1_GW_DRAM_IO16, GUSP(gus, GF1REGSEL));
315 outsw(GUSP(gus, GF1DATALOW), buf, len >> 1);
316 } else {
317 outsb(GUSP(gus, DRAM), buf, len);
318 }
319 spin_unlock_irqrestore(&gus->reg_lock, flags);
320 buf += 512;
321 pos += 512;
322 } else {
323 invert = invert ? 0x80 : 0x00;
324 if (w16) {
325 len >>= 1;
326 while (len--) {
327 snd_gf1_poke(gus, pos++, *buf++);
328 snd_gf1_poke(gus, pos++, *buf++ ^ invert);
329 }
330 } else {
331 while (len--)
332 snd_gf1_poke(gus, pos++, *buf++ ^ invert);
333 }
334 }
335 if (count > 0 && !in_interrupt()) {
336 set_current_state(TASK_INTERRUPTIBLE);
337 schedule_timeout(1);
338 if (signal_pending(current))
339 return -EAGAIN;
340 }
341 }
342 return 0;
343}
344
345static int snd_gf1_pcm_playback_copy(snd_pcm_substream_t *substream,
346 int voice,
347 snd_pcm_uframes_t pos,
348 void __user *src,
349 snd_pcm_uframes_t count)
350{
351 snd_pcm_runtime_t *runtime = substream->runtime;
352 gus_pcm_private_t *pcmp = runtime->private_data;
353 unsigned int bpos, len;
354
355 bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
356 len = samples_to_bytes(runtime, count);
357 snd_assert(bpos <= pcmp->dma_size, return -EIO);
358 snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
359 if (copy_from_user(runtime->dma_area + bpos, src, len))
360 return -EFAULT;
361 if (snd_gf1_pcm_use_dma && len > 32) {
362 return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len);
363 } else {
364 snd_gus_card_t *gus = pcmp->gus;
365 int err, w16, invert;
366
367 w16 = (snd_pcm_format_width(runtime->format) == 16);
368 invert = snd_pcm_format_unsigned(runtime->format);
369 if ((err = snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, pcmp->memory + bpos, len, w16, invert)) < 0)
370 return err;
371 }
372 return 0;
373}
374
375static int snd_gf1_pcm_playback_silence(snd_pcm_substream_t *substream,
376 int voice,
377 snd_pcm_uframes_t pos,
378 snd_pcm_uframes_t count)
379{
380 snd_pcm_runtime_t *runtime = substream->runtime;
381 gus_pcm_private_t *pcmp = runtime->private_data;
382 unsigned int bpos, len;
383
384 bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
385 len = samples_to_bytes(runtime, count);
386 snd_assert(bpos <= pcmp->dma_size, return -EIO);
387 snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
388 snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, count);
389 if (snd_gf1_pcm_use_dma && len > 32) {
390 return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len);
391 } else {
392 snd_gus_card_t *gus = pcmp->gus;
393 int err, w16, invert;
394
395 w16 = (snd_pcm_format_width(runtime->format) == 16);
396 invert = snd_pcm_format_unsigned(runtime->format);
397 if ((err = snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos, pcmp->memory + bpos, len, w16, invert)) < 0)
398 return err;
399 }
400 return 0;
401}
402
403static int snd_gf1_pcm_playback_hw_params(snd_pcm_substream_t * substream,
404 snd_pcm_hw_params_t * hw_params)
405{
406 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
407 snd_pcm_runtime_t *runtime = substream->runtime;
408 gus_pcm_private_t *pcmp = runtime->private_data;
409 int err;
410
411 if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
412 return err;
413 if (err > 0) { /* change */
414 snd_gf1_mem_block_t *block;
415 if (pcmp->memory > 0) {
416 snd_gf1_mem_free(&gus->gf1.mem_alloc, pcmp->memory);
417 pcmp->memory = 0;
418 }
419 if ((block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
420 SNDRV_GF1_MEM_OWNER_DRIVER,
421 "GF1 PCM",
422 runtime->dma_bytes, 1, 32,
423 NULL)) == NULL)
424 return -ENOMEM;
425 pcmp->memory = block->ptr;
426 }
427 pcmp->voices = params_channels(hw_params);
428 if (pcmp->pvoices[0] == NULL) {
429 if ((pcmp->pvoices[0] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0)) == NULL)
430 return -ENOMEM;
431 pcmp->pvoices[0]->handler_wave = snd_gf1_pcm_interrupt_wave;
432 pcmp->pvoices[0]->handler_volume = snd_gf1_pcm_interrupt_volume;
433 pcmp->pvoices[0]->volume_change = snd_gf1_pcm_volume_change;
434 pcmp->pvoices[0]->private_data = pcmp;
435 }
436 if (pcmp->voices > 1 && pcmp->pvoices[1] == NULL) {
437 if ((pcmp->pvoices[1] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0)) == NULL)
438 return -ENOMEM;
439 pcmp->pvoices[1]->handler_wave = snd_gf1_pcm_interrupt_wave;
440 pcmp->pvoices[1]->handler_volume = snd_gf1_pcm_interrupt_volume;
441 pcmp->pvoices[1]->volume_change = snd_gf1_pcm_volume_change;
442 pcmp->pvoices[1]->private_data = pcmp;
443 } else if (pcmp->voices == 1) {
444 if (pcmp->pvoices[1]) {
445 snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[1]);
446 pcmp->pvoices[1] = NULL;
447 }
448 }
449 return 0;
450}
451
452static int snd_gf1_pcm_playback_hw_free(snd_pcm_substream_t * substream)
453{
454 snd_pcm_runtime_t *runtime = substream->runtime;
455 gus_pcm_private_t *pcmp = runtime->private_data;
456
457 snd_pcm_lib_free_pages(substream);
458 if (pcmp->pvoices[0]) {
459 snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[0]);
460 pcmp->pvoices[0] = NULL;
461 }
462 if (pcmp->pvoices[1]) {
463 snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[1]);
464 pcmp->pvoices[1] = NULL;
465 }
466 if (pcmp->memory > 0) {
467 snd_gf1_mem_free(&pcmp->gus->gf1.mem_alloc, pcmp->memory);
468 pcmp->memory = 0;
469 }
470 return 0;
471}
472
473static int snd_gf1_pcm_playback_prepare(snd_pcm_substream_t * substream)
474{
475 snd_pcm_runtime_t *runtime = substream->runtime;
476 gus_pcm_private_t *pcmp = runtime->private_data;
477
478 pcmp->bpos = 0;
479 pcmp->dma_size = snd_pcm_lib_buffer_bytes(substream);
480 pcmp->block_size = snd_pcm_lib_period_bytes(substream);
481 pcmp->blocks = pcmp->dma_size / pcmp->block_size;
482 return 0;
483}
484
485static int snd_gf1_pcm_playback_trigger(snd_pcm_substream_t * substream,
486 int cmd)
487{
488 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
489 snd_pcm_runtime_t *runtime = substream->runtime;
490 gus_pcm_private_t *pcmp = runtime->private_data;
491 int voice;
492
493 if (cmd == SNDRV_PCM_TRIGGER_START) {
494 snd_gf1_pcm_trigger_up(substream);
495 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
496 spin_lock(&pcmp->lock);
497 pcmp->flags &= ~SNDRV_GF1_PCM_PFLG_ACTIVE;
498 spin_unlock(&pcmp->lock);
499 voice = pcmp->pvoices[0]->number;
500 snd_gf1_stop_voices(gus, voice, voice);
501 if (pcmp->pvoices[1]) {
502 voice = pcmp->pvoices[1]->number;
503 snd_gf1_stop_voices(gus, voice, voice);
504 }
505 } else {
506 return -EINVAL;
507 }
508 return 0;
509}
510
511static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(snd_pcm_substream_t * substream)
512{
513 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
514 snd_pcm_runtime_t *runtime = substream->runtime;
515 gus_pcm_private_t *pcmp = runtime->private_data;
516 unsigned int pos;
517 unsigned char voice_ctrl;
518
519 pos = 0;
520 spin_lock(&gus->reg_lock);
521 if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {
522 snd_gf1_select_voice(gus, pcmp->pvoices[0]->number);
523 voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
524 pos = (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4) - pcmp->memory;
525 if (substream->runtime->channels > 1)
526 pos <<= 1;
527 pos = bytes_to_frames(runtime, pos);
528 }
529 spin_unlock(&gus->reg_lock);
530 return pos;
531}
532
533static ratnum_t clock = {
534 .num = 9878400/16,
535 .den_min = 2,
536 .den_max = 257,
537 .den_step = 1,
538};
539
540static snd_pcm_hw_constraint_ratnums_t hw_constraints_clocks = {
541 .nrats = 1,
542 .rats = &clock,
543};
544
545static int snd_gf1_pcm_capture_hw_params(snd_pcm_substream_t * substream,
546 snd_pcm_hw_params_t * hw_params)
547{
548 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
549
550 gus->c_dma_size = params_buffer_bytes(hw_params);
551 gus->c_period_size = params_period_bytes(hw_params);
552 gus->c_pos = 0;
553 gus->gf1.pcm_rcntrl_reg = 0x21; /* IRQ at end, enable & start */
554 if (params_channels(hw_params) > 1)
555 gus->gf1.pcm_rcntrl_reg |= 2;
556 if (gus->gf1.dma2 > 3)
557 gus->gf1.pcm_rcntrl_reg |= 4;
558 if (snd_pcm_format_unsigned(params_format(hw_params)))
559 gus->gf1.pcm_rcntrl_reg |= 0x80;
560 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
561}
562
563static int snd_gf1_pcm_capture_hw_free(snd_pcm_substream_t * substream)
564{
565 return snd_pcm_lib_free_pages(substream);
566}
567
568static int snd_gf1_pcm_capture_prepare(snd_pcm_substream_t * substream)
569{
570 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
571 snd_pcm_runtime_t *runtime = substream->runtime;
572
573 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RECORD_RATE, runtime->rate_den - 2);
574 snd_gf1_i_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, 0); /* disable sampling */
575 snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL); /* Sampling Control Register */
576 snd_dma_program(gus->gf1.dma2, runtime->dma_addr, gus->c_period_size, DMA_MODE_READ);
577 return 0;
578}
579
580static int snd_gf1_pcm_capture_trigger(snd_pcm_substream_t * substream,
581 int cmd)
582{
583 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
584 int val;
585
586 if (cmd == SNDRV_PCM_TRIGGER_START) {
587 val = gus->gf1.pcm_rcntrl_reg;
588 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
589 val = 0;
590 } else {
591 return -EINVAL;
592 }
593
594 spin_lock(&gus->reg_lock);
595 snd_gf1_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, val);
596 snd_gf1_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL);
597 spin_unlock(&gus->reg_lock);
598 return 0;
599}
600
601static snd_pcm_uframes_t snd_gf1_pcm_capture_pointer(snd_pcm_substream_t * substream)
602{
603 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
604 int pos = snd_dma_pointer(gus->gf1.dma2, gus->c_period_size);
605 pos = bytes_to_frames(substream->runtime, (gus->c_pos + pos) % gus->c_dma_size);
606 return pos;
607}
608
609static void snd_gf1_pcm_interrupt_dma_read(snd_gus_card_t * gus)
610{
611 snd_gf1_i_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, 0); /* disable sampling */
612 snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL); /* Sampling Control Register */
613 if (gus->pcm_cap_substream != NULL) {
614 snd_gf1_pcm_capture_prepare(gus->pcm_cap_substream);
615 snd_gf1_pcm_capture_trigger(gus->pcm_cap_substream, SNDRV_PCM_TRIGGER_START);
616 gus->c_pos += gus->c_period_size;
617 snd_pcm_period_elapsed(gus->pcm_cap_substream);
618 }
619}
620
621static snd_pcm_hardware_t snd_gf1_pcm_playback =
622{
623 .info = SNDRV_PCM_INFO_NONINTERLEAVED,
624 .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
625 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
626 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
627 .rate_min = 5510,
628 .rate_max = 48000,
629 .channels_min = 1,
630 .channels_max = 2,
631 .buffer_bytes_max = (128*1024),
632 .period_bytes_min = 64,
633 .period_bytes_max = (128*1024),
634 .periods_min = 1,
635 .periods_max = 1024,
636 .fifo_size = 0,
637};
638
639static snd_pcm_hardware_t snd_gf1_pcm_capture =
640{
641 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
642 SNDRV_PCM_INFO_MMAP_VALID),
643 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8,
644 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100,
645 .rate_min = 5510,
646 .rate_max = 44100,
647 .channels_min = 1,
648 .channels_max = 2,
649 .buffer_bytes_max = (128*1024),
650 .period_bytes_min = 64,
651 .period_bytes_max = (128*1024),
652 .periods_min = 1,
653 .periods_max = 1024,
654 .fifo_size = 0,
655};
656
657static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime)
658{
659 gus_pcm_private_t * pcmp = runtime->private_data;
660 kfree(pcmp);
661}
662
663static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream)
664{
665 gus_pcm_private_t *pcmp;
666 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
667 snd_pcm_runtime_t *runtime = substream->runtime;
668 int err;
669
670 pcmp = kcalloc(1, sizeof(*pcmp), GFP_KERNEL);
671 if (pcmp == NULL)
672 return -ENOMEM;
673 pcmp->gus = gus;
674 spin_lock_init(&pcmp->lock);
675 init_waitqueue_head(&pcmp->sleep);
676 atomic_set(&pcmp->dma_count, 0);
677
678 runtime->private_data = pcmp;
679 runtime->private_free = snd_gf1_pcm_playback_free;
680
681#if 0
682 printk("playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n", (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
683#endif
684 if ((err = snd_gf1_dma_init(gus)) < 0)
685 return err;
686 pcmp->flags = SNDRV_GF1_PCM_PFLG_NONE;
687 pcmp->substream = substream;
688 runtime->hw = snd_gf1_pcm_playback;
689 snd_pcm_limit_isa_dma_size(gus->gf1.dma1, &runtime->hw.buffer_bytes_max);
690 snd_pcm_limit_isa_dma_size(gus->gf1.dma1, &runtime->hw.period_bytes_max);
691 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
692 return 0;
693}
694
695static int snd_gf1_pcm_playback_close(snd_pcm_substream_t * substream)
696{
697 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
698 snd_pcm_runtime_t *runtime = substream->runtime;
699 gus_pcm_private_t *pcmp = runtime->private_data;
700
701 if (!wait_event_timeout(pcmp->sleep, (atomic_read(&pcmp->dma_count) <= 0), 2*HZ))
702 snd_printk("gf1 pcm - serious DMA problem\n");
703
704 snd_gf1_dma_done(gus);
705 return 0;
706}
707
708static int snd_gf1_pcm_capture_open(snd_pcm_substream_t * substream)
709{
710 snd_pcm_runtime_t *runtime = substream->runtime;
711 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
712
713 gus->gf1.interrupt_handler_dma_read = snd_gf1_pcm_interrupt_dma_read;
714 gus->pcm_cap_substream = substream;
715 substream->runtime->hw = snd_gf1_pcm_capture;
716 snd_pcm_limit_isa_dma_size(gus->gf1.dma2, &runtime->hw.buffer_bytes_max);
717 snd_pcm_limit_isa_dma_size(gus->gf1.dma2, &runtime->hw.period_bytes_max);
718 snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
719 &hw_constraints_clocks);
720 return 0;
721}
722
723static int snd_gf1_pcm_capture_close(snd_pcm_substream_t * substream)
724{
725 snd_gus_card_t *gus = snd_pcm_substream_chip(substream);
726
727 gus->pcm_cap_substream = NULL;
728 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_DMA_READ);
729 return 0;
730}
731
732static void snd_gf1_pcm_free(snd_pcm_t *pcm)
733{
734 snd_gus_card_t *gus = pcm->private_data;
735 gus->pcm = NULL;
736 snd_pcm_lib_preallocate_free_for_all(pcm);
737}
738
739static int snd_gf1_pcm_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
740{
741 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
742 uinfo->count = 2;
743 uinfo->value.integer.min = 0;
744 uinfo->value.integer.max = 127;
745 return 0;
746}
747
748static int snd_gf1_pcm_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
749{
750 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
751 unsigned long flags;
752
753 spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);
754 ucontrol->value.integer.value[0] = gus->gf1.pcm_volume_level_left1;
755 ucontrol->value.integer.value[1] = gus->gf1.pcm_volume_level_right1;
756 spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);
757 return 0;
758}
759
760static int snd_gf1_pcm_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
761{
762 snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);
763 unsigned long flags;
764 int change;
765 unsigned int idx;
766 unsigned short val1, val2, vol;
767 gus_pcm_private_t *pcmp;
768 snd_gus_voice_t *pvoice;
769
770 val1 = ucontrol->value.integer.value[0] & 127;
771 val2 = ucontrol->value.integer.value[1] & 127;
772 spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);
773 change = val1 != gus->gf1.pcm_volume_level_left1 ||
774 val2 != gus->gf1.pcm_volume_level_right1;
775 gus->gf1.pcm_volume_level_left1 = val1;
776 gus->gf1.pcm_volume_level_right1 = val2;
777 gus->gf1.pcm_volume_level_left = snd_gf1_lvol_to_gvol_raw(val1 << 9) << 4;
778 gus->gf1.pcm_volume_level_right = snd_gf1_lvol_to_gvol_raw(val2 << 9) << 4;
779 spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);
780 /* are we active? */
781 spin_lock_irqsave(&gus->voice_alloc, flags);
782 for (idx = 0; idx < 32; idx++) {
783 pvoice = &gus->gf1.voices[idx];
784 if (!pvoice->pcm)
785 continue;
786 pcmp = pvoice->private_data;
787 if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))
788 continue;
789 /* load real volume - better precision */
790 spin_lock_irqsave(&gus->reg_lock, flags);
791 snd_gf1_select_voice(gus, pvoice->number);
792 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
793 vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
794 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);
795 pcmp->final_volume = 1;
796 spin_unlock_irqrestore(&gus->reg_lock, flags);
797 }
798 spin_unlock_irqrestore(&gus->voice_alloc, flags);
799 return change;
800}
801
802static snd_kcontrol_new_t snd_gf1_pcm_volume_control =
803{
804 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
805 .name = "PCM Playback Volume",
806 .info = snd_gf1_pcm_volume_info,
807 .get = snd_gf1_pcm_volume_get,
808 .put = snd_gf1_pcm_volume_put
809};
810
811static snd_kcontrol_new_t snd_gf1_pcm_volume_control1 =
812{
813 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
814 .name = "GPCM Playback Volume",
815 .info = snd_gf1_pcm_volume_info,
816 .get = snd_gf1_pcm_volume_get,
817 .put = snd_gf1_pcm_volume_put
818};
819
820static snd_pcm_ops_t snd_gf1_pcm_playback_ops = {
821 .open = snd_gf1_pcm_playback_open,
822 .close = snd_gf1_pcm_playback_close,
823 .ioctl = snd_pcm_lib_ioctl,
824 .hw_params = snd_gf1_pcm_playback_hw_params,
825 .hw_free = snd_gf1_pcm_playback_hw_free,
826 .prepare = snd_gf1_pcm_playback_prepare,
827 .trigger = snd_gf1_pcm_playback_trigger,
828 .pointer = snd_gf1_pcm_playback_pointer,
829 .copy = snd_gf1_pcm_playback_copy,
830 .silence = snd_gf1_pcm_playback_silence,
831};
832
833static snd_pcm_ops_t snd_gf1_pcm_capture_ops = {
834 .open = snd_gf1_pcm_capture_open,
835 .close = snd_gf1_pcm_capture_close,
836 .ioctl = snd_pcm_lib_ioctl,
837 .hw_params = snd_gf1_pcm_capture_hw_params,
838 .hw_free = snd_gf1_pcm_capture_hw_free,
839 .prepare = snd_gf1_pcm_capture_prepare,
840 .trigger = snd_gf1_pcm_capture_trigger,
841 .pointer = snd_gf1_pcm_capture_pointer,
842};
843
844int snd_gf1_pcm_new(snd_gus_card_t * gus, int pcm_dev, int control_index, snd_pcm_t ** rpcm)
845{
846 snd_card_t *card;
847 snd_kcontrol_t *kctl;
848 snd_pcm_t *pcm;
849 snd_pcm_substream_t *substream;
850 int capture, err;
851
852 if (rpcm)
853 *rpcm = NULL;
854 card = gus->card;
855 capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0;
856 err = snd_pcm_new(card,
857 gus->interwave ? "AMD InterWave" : "GF1",
858 pcm_dev,
859 gus->gf1.pcm_channels / 2,
860 capture,
861 &pcm);
862 if (err < 0)
863 return err;
864 pcm->private_data = gus;
865 pcm->private_free = snd_gf1_pcm_free;
866 /* playback setup */
867 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_gf1_pcm_playback_ops);
868
869 for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
870 snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
871 snd_dma_isa_data(),
872 64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024);
873
874 pcm->info_flags = 0;
875 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
876 if (capture) {
877 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_gf1_pcm_capture_ops);
878 if (gus->gf1.dma2 == gus->gf1.dma1)
879 pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
880 snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
881 SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(),
882 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024);
883 }
884 strcpy(pcm->name, pcm->id);
885 if (gus->interwave) {
886 sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
887 }
888 strcat(pcm->name, " (synth)");
889 gus->pcm = pcm;
890
891 if (gus->codec_flag)
892 kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus);
893 else
894 kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus);
895 if ((err = snd_ctl_add(card, kctl)) < 0)
896 return err;
897 kctl->id.index = control_index;
898
899 if (rpcm)
900 *rpcm = pcm;
901 return 0;
902}
903
diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c
new file mode 100644
index 000000000000..b4e66f6a10ae
--- /dev/null
+++ b/sound/isa/gus/gus_reset.c
@@ -0,0 +1,413 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 *
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/delay.h>
23#include <linux/interrupt.h>
24#include <linux/time.h>
25#include <sound/core.h>
26#include <sound/gus.h>
27
28extern void snd_gf1_timers_init(snd_gus_card_t * gus);
29extern void snd_gf1_timers_done(snd_gus_card_t * gus);
30extern int snd_gf1_synth_init(snd_gus_card_t * gus);
31extern void snd_gf1_synth_done(snd_gus_card_t * gus);
32
33/*
34 * ok.. default interrupt handlers...
35 */
36
37static void snd_gf1_default_interrupt_handler_midi_out(snd_gus_card_t * gus)
38{
39 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd &= ~0x20);
40}
41
42static void snd_gf1_default_interrupt_handler_midi_in(snd_gus_card_t * gus)
43{
44 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd &= ~0x80);
45}
46
47static void snd_gf1_default_interrupt_handler_timer1(snd_gus_card_t * gus)
48{
49 snd_gf1_i_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, gus->gf1.timer_enabled &= ~4);
50}
51
52static void snd_gf1_default_interrupt_handler_timer2(snd_gus_card_t * gus)
53{
54 snd_gf1_i_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, gus->gf1.timer_enabled &= ~8);
55}
56
57static void snd_gf1_default_interrupt_handler_wave_and_volume(snd_gus_card_t * gus, snd_gus_voice_t * voice)
58{
59 snd_gf1_i_ctrl_stop(gus, 0x00);
60 snd_gf1_i_ctrl_stop(gus, 0x0d);
61}
62
63static void snd_gf1_default_interrupt_handler_dma_write(snd_gus_card_t * gus)
64{
65 snd_gf1_i_write8(gus, 0x41, 0x00);
66}
67
68static void snd_gf1_default_interrupt_handler_dma_read(snd_gus_card_t * gus)
69{
70 snd_gf1_i_write8(gus, 0x49, 0x00);
71}
72
73void snd_gf1_set_default_handlers(snd_gus_card_t * gus, unsigned int what)
74{
75 if (what & SNDRV_GF1_HANDLER_MIDI_OUT)
76 gus->gf1.interrupt_handler_midi_out = snd_gf1_default_interrupt_handler_midi_out;
77 if (what & SNDRV_GF1_HANDLER_MIDI_IN)
78 gus->gf1.interrupt_handler_midi_in = snd_gf1_default_interrupt_handler_midi_in;
79 if (what & SNDRV_GF1_HANDLER_TIMER1)
80 gus->gf1.interrupt_handler_timer1 = snd_gf1_default_interrupt_handler_timer1;
81 if (what & SNDRV_GF1_HANDLER_TIMER2)
82 gus->gf1.interrupt_handler_timer2 = snd_gf1_default_interrupt_handler_timer2;
83 if (what & SNDRV_GF1_HANDLER_VOICE) {
84 snd_gus_voice_t *voice;
85
86 voice = &gus->gf1.voices[what & 0xffff];
87 voice->handler_wave =
88 voice->handler_volume = snd_gf1_default_interrupt_handler_wave_and_volume;
89 voice->handler_effect = NULL;
90 voice->volume_change = NULL;
91 }
92 if (what & SNDRV_GF1_HANDLER_DMA_WRITE)
93 gus->gf1.interrupt_handler_dma_write = snd_gf1_default_interrupt_handler_dma_write;
94 if (what & SNDRV_GF1_HANDLER_DMA_READ)
95 gus->gf1.interrupt_handler_dma_read = snd_gf1_default_interrupt_handler_dma_read;
96}
97
98/*
99
100 */
101
102static void snd_gf1_clear_regs(snd_gus_card_t * gus)
103{
104 unsigned long flags;
105
106 spin_lock_irqsave(&gus->reg_lock, flags);
107 inb(GUSP(gus, IRQSTAT));
108 snd_gf1_write8(gus, 0x41, 0); /* DRAM DMA Control Register */
109 snd_gf1_write8(gus, 0x45, 0); /* Timer Control */
110 snd_gf1_write8(gus, 0x49, 0); /* Sampling Control Register */
111 spin_unlock_irqrestore(&gus->reg_lock, flags);
112}
113
114static void snd_gf1_look_regs(snd_gus_card_t * gus)
115{
116 unsigned long flags;
117
118 spin_lock_irqsave(&gus->reg_lock, flags);
119 snd_gf1_look8(gus, 0x41); /* DRAM DMA Control Register */
120 snd_gf1_look8(gus, 0x49); /* Sampling Control Register */
121 inb(GUSP(gus, IRQSTAT));
122 snd_gf1_read8(gus, 0x0f); /* IRQ Source Register */
123 spin_unlock_irqrestore(&gus->reg_lock, flags);
124}
125
126/*
127 * put selected GF1 voices to initial stage...
128 */
129
130void snd_gf1_smart_stop_voice(snd_gus_card_t * gus, unsigned short voice)
131{
132 unsigned long flags;
133
134 spin_lock_irqsave(&gus->reg_lock, flags);
135 snd_gf1_select_voice(gus, voice);
136#if 0
137 printk(" -%i- smart stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));
138#endif
139 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
140 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
141 spin_unlock_irqrestore(&gus->reg_lock, flags);
142}
143
144void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice)
145{
146 unsigned long flags;
147
148 spin_lock_irqsave(&gus->reg_lock, flags);
149 snd_gf1_select_voice(gus, voice);
150#if 0
151 printk(" -%i- stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));
152#endif
153 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
154 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
155 if (gus->gf1.enh_mode)
156 snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, 0);
157 spin_unlock_irqrestore(&gus->reg_lock, flags);
158#if 0
159 snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_VIBRATO);
160 snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_TREMOLO);
161#endif
162}
163
164void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max)
165{
166 unsigned long flags;
167 unsigned int daddr;
168 unsigned short i, w_16;
169
170 daddr = gus->gf1.default_voice_address << 4;
171 for (i = v_min; i <= v_max; i++) {
172#if 0
173 if (gus->gf1.syn_voices)
174 gus->gf1.syn_voices[i].flags = ~VFLG_DYNAMIC;
175#endif
176 spin_lock_irqsave(&gus->reg_lock, flags);
177 snd_gf1_select_voice(gus, i);
178 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); /* Voice Control Register = voice stop */
179 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); /* Volume Ramp Control Register = ramp off */
180 if (gus->gf1.enh_mode)
181 snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, gus->gf1.memory ? 0x02 : 0x82); /* Deactivate voice */
182 w_16 = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & 0x04;
183 snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, 0x400);
184 snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, daddr, w_16);
185 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, daddr, w_16);
186 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, 0);
187 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, 0);
188 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, 0);
189 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0);
190 snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, daddr, w_16);
191 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, 7);
192 if (gus->gf1.enh_mode) {
193 snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, 0);
194 snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, 0);
195 snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, 0);
196 }
197 spin_unlock_irqrestore(&gus->reg_lock, flags);
198#if 0
199 snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_VIBRATO);
200 snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_TREMOLO);
201#endif
202 }
203}
204
205void snd_gf1_stop_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max)
206{
207 unsigned long flags;
208 short i, ramp_ok;
209 unsigned short ramp_end;
210
211 if (!in_interrupt()) { /* this can't be done in interrupt */
212 for (i = v_min, ramp_ok = 0; i <= v_max; i++) {
213 spin_lock_irqsave(&gus->reg_lock, flags);
214 snd_gf1_select_voice(gus, i);
215 ramp_end = snd_gf1_read16(gus, 9) >> 8;
216 if (ramp_end > SNDRV_GF1_MIN_OFFSET) {
217 ramp_ok++;
218 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, 20); /* ramp rate */
219 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, SNDRV_GF1_MIN_OFFSET); /* ramp start */
220 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, ramp_end); /* ramp end */
221 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, 0x40); /* ramp down */
222 if (gus->gf1.enh_mode) {
223 snd_gf1_delay(gus);
224 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, 0x40);
225 }
226 }
227 spin_unlock_irqrestore(&gus->reg_lock, flags);
228 }
229 msleep_interruptible(50);
230 }
231 snd_gf1_clear_voices(gus, v_min, v_max);
232}
233
234static void snd_gf1_alloc_voice_use(snd_gus_card_t * gus,
235 snd_gus_voice_t * pvoice,
236 int type, int client, int port)
237{
238 pvoice->use = 1;
239 switch (type) {
240 case SNDRV_GF1_VOICE_TYPE_PCM:
241 gus->gf1.pcm_alloc_voices++;
242 pvoice->pcm = 1;
243 break;
244 case SNDRV_GF1_VOICE_TYPE_SYNTH:
245 pvoice->synth = 1;
246 pvoice->client = client;
247 pvoice->port = port;
248 break;
249 case SNDRV_GF1_VOICE_TYPE_MIDI:
250 pvoice->midi = 1;
251 pvoice->client = client;
252 pvoice->port = port;
253 break;
254 }
255}
256
257snd_gus_voice_t *snd_gf1_alloc_voice(snd_gus_card_t * gus, int type, int client, int port)
258{
259 snd_gus_voice_t *pvoice;
260 unsigned long flags;
261 int idx;
262
263 spin_lock_irqsave(&gus->voice_alloc, flags);
264 if (type == SNDRV_GF1_VOICE_TYPE_PCM) {
265 if (gus->gf1.pcm_alloc_voices >= gus->gf1.pcm_channels) {
266 spin_unlock_irqrestore(&gus->voice_alloc, flags);
267 return NULL;
268 }
269 }
270 for (idx = 0; idx < 32; idx++) {
271 pvoice = &gus->gf1.voices[idx];
272 if (!pvoice->use) {
273 snd_gf1_alloc_voice_use(gus, pvoice, type, client, port);
274 spin_unlock_irqrestore(&gus->voice_alloc, flags);
275 return pvoice;
276 }
277 }
278 for (idx = 0; idx < 32; idx++) {
279 pvoice = &gus->gf1.voices[idx];
280 if (pvoice->midi && !pvoice->client) {
281 snd_gf1_clear_voices(gus, pvoice->number, pvoice->number);
282 snd_gf1_alloc_voice_use(gus, pvoice, type, client, port);
283 spin_unlock_irqrestore(&gus->voice_alloc, flags);
284 return pvoice;
285 }
286 }
287 spin_unlock_irqrestore(&gus->voice_alloc, flags);
288 return NULL;
289}
290
291void snd_gf1_free_voice(snd_gus_card_t * gus, snd_gus_voice_t *voice)
292{
293 unsigned long flags;
294 void (*private_free)(snd_gus_voice_t *voice);
295 void *private_data;
296
297 if (voice == NULL || !voice->use)
298 return;
299 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_VOICE | voice->number);
300 snd_gf1_clear_voices(gus, voice->number, voice->number);
301 spin_lock_irqsave(&gus->voice_alloc, flags);
302 private_free = voice->private_free;
303 private_data = voice->private_data;
304 voice->private_free = NULL;
305 voice->private_data = NULL;
306 if (voice->pcm)
307 gus->gf1.pcm_alloc_voices--;
308 voice->use = voice->pcm = 0;
309 voice->sample_ops = NULL;
310 spin_unlock_irqrestore(&gus->voice_alloc, flags);
311 if (private_free)
312 private_free(voice);
313}
314
315/*
316 * call this function only by start of driver
317 */
318
319int snd_gf1_start(snd_gus_card_t * gus)
320{
321 unsigned long flags;
322 unsigned int i;
323
324 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
325 udelay(160);
326 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* disable IRQ & DAC */
327 udelay(160);
328 snd_gf1_i_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac);
329
330 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_ALL);
331 for (i = 0; i < 32; i++) {
332 gus->gf1.voices[i].number = i;
333 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_VOICE | i);
334 }
335
336 snd_gf1_uart_cmd(gus, 0x03); /* huh.. this cleanup took me some time... */
337
338 if (gus->gf1.enh_mode) { /* enhanced mode !!!! */
339 snd_gf1_i_write8(gus, SNDRV_GF1_GB_GLOBAL_MODE, snd_gf1_i_look8(gus, SNDRV_GF1_GB_GLOBAL_MODE) | 0x01);
340 snd_gf1_i_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
341 }
342 snd_gf1_clear_regs(gus);
343 snd_gf1_select_active_voices(gus);
344 snd_gf1_delay(gus);
345 gus->gf1.default_voice_address = gus->gf1.memory > 0 ? 0 : 512 - 8;
346 /* initialize LFOs & clear LFOs memory */
347 if (gus->gf1.enh_mode && gus->gf1.memory) {
348 gus->gf1.hw_lfo = 1;
349 gus->gf1.default_voice_address += 1024;
350 } else {
351 gus->gf1.sw_lfo = 1;
352 }
353#if 0
354 snd_gf1_lfo_init(gus);
355#endif
356 if (gus->gf1.memory > 0)
357 for (i = 0; i < 4; i++)
358 snd_gf1_poke(gus, gus->gf1.default_voice_address + i, 0);
359 snd_gf1_clear_regs(gus);
360 snd_gf1_clear_voices(gus, 0, 31);
361 snd_gf1_look_regs(gus);
362 udelay(160);
363 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 7); /* Reset Register = IRQ enable, DAC enable */
364 udelay(160);
365 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 7); /* Reset Register = IRQ enable, DAC enable */
366 if (gus->gf1.enh_mode) { /* enhanced mode !!!! */
367 snd_gf1_i_write8(gus, SNDRV_GF1_GB_GLOBAL_MODE, snd_gf1_i_look8(gus, SNDRV_GF1_GB_GLOBAL_MODE) | 0x01);
368 snd_gf1_i_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
369 }
370 while ((snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ) & 0xc0) != 0xc0);
371
372 spin_lock_irqsave(&gus->reg_lock, flags);
373 outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));
374 outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
375 spin_unlock_irqrestore(&gus->reg_lock, flags);
376
377 snd_gf1_timers_init(gus);
378 snd_gf1_look_regs(gus);
379 snd_gf1_mem_init(gus);
380 snd_gf1_mem_proc_init(gus);
381#ifdef CONFIG_SND_DEBUG
382 snd_gus_irq_profile_init(gus);
383#endif
384
385#if 0
386 if (gus->pnp_flag) {
387 if (gus->chip.playback_fifo_size > 0)
388 snd_gf1_i_write16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR, gus->chip.playback_fifo_block->ptr >> 8);
389 if (gus->chip.record_fifo_size > 0)
390 snd_gf1_i_write16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR, gus->chip.record_fifo_block->ptr >> 8);
391 snd_gf1_i_write16(gus, SNDRV_GF1_GW_FIFO_SIZE, gus->chip.interwave_fifo_reg);
392 }
393#endif
394
395 return 0;
396}
397
398/*
399 * call this function only by shutdown of driver
400 */
401
402int snd_gf1_stop(snd_gus_card_t * gus)
403{
404 snd_gf1_i_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0); /* stop all timers */
405 snd_gf1_stop_voices(gus, 0, 31); /* stop all voices */
406 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* disable IRQ & DAC */
407 snd_gf1_timers_done(gus);
408 snd_gf1_mem_done(gus);
409#if 0
410 snd_gf1_lfo_done(gus);
411#endif
412 return 0;
413}
diff --git a/sound/isa/gus/gus_sample.c b/sound/isa/gus/gus_sample.c
new file mode 100644
index 000000000000..4290e03acd51
--- /dev/null
+++ b/sound/isa/gus/gus_sample.c
@@ -0,0 +1,155 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Sample support
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/time.h>
24#include <sound/core.h>
25#include <sound/gus.h>
26
27/*
28 *
29 */
30
31static void select_instrument(snd_gus_card_t * gus, snd_gus_voice_t * v)
32{
33 snd_seq_kinstr_t *instr;
34
35#if 0
36 printk("select instrument: cluster = %li, std = 0x%x, bank = %i, prg = %i\n",
37 v->instr.cluster,
38 v->instr.std,
39 v->instr.bank,
40 v->instr.prg);
41#endif
42 instr = snd_seq_instr_find(gus->gf1.ilist, &v->instr, 0, 1);
43 if (instr != NULL) {
44 if (instr->ops) {
45 if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE))
46 snd_gf1_simple_init(v);
47 }
48 snd_seq_instr_free_use(gus->gf1.ilist, instr);
49 }
50}
51
52/*
53 *
54 */
55
56static void event_sample(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
57{
58 if (v->sample_ops && v->sample_ops->sample_stop)
59 v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
60 v->instr.std = ev->data.sample.param.sample.std;
61 if (v->instr.std & 0xff000000) { /* private instrument */
62 v->instr.std &= 0x00ffffff;
63 v->instr.std |= (unsigned int)ev->source.client << 24;
64 }
65 v->instr.bank = ev->data.sample.param.sample.bank;
66 v->instr.prg = ev->data.sample.param.sample.prg;
67 select_instrument(p->gus, v);
68}
69
70static void event_cluster(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
71{
72 if (v->sample_ops && v->sample_ops->sample_stop)
73 v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
74 v->instr.cluster = ev->data.sample.param.cluster.cluster;
75 select_instrument(p->gus, v);
76}
77
78static void event_start(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
79{
80 if (v->sample_ops && v->sample_ops->sample_start)
81 v->sample_ops->sample_start(p->gus, v, ev->data.sample.param.position);
82}
83
84static void event_stop(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
85{
86 if (v->sample_ops && v->sample_ops->sample_stop)
87 v->sample_ops->sample_stop(p->gus, v, ev->data.sample.param.stop_mode);
88}
89
90static void event_freq(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
91{
92 if (v->sample_ops && v->sample_ops->sample_freq)
93 v->sample_ops->sample_freq(p->gus, v, ev->data.sample.param.frequency);
94}
95
96static void event_volume(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
97{
98 if (v->sample_ops && v->sample_ops->sample_volume)
99 v->sample_ops->sample_volume(p->gus, v, &ev->data.sample.param.volume);
100}
101
102static void event_loop(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
103{
104 if (v->sample_ops && v->sample_ops->sample_loop)
105 v->sample_ops->sample_loop(p->gus, v, &ev->data.sample.param.loop);
106}
107
108static void event_position(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
109{
110 if (v->sample_ops && v->sample_ops->sample_pos)
111 v->sample_ops->sample_pos(p->gus, v, ev->data.sample.param.position);
112}
113
114static void event_private1(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v)
115{
116 if (v->sample_ops && v->sample_ops->sample_private1)
117 v->sample_ops->sample_private1(p->gus, v, (unsigned char *)&ev->data.sample.param.raw8);
118}
119
120typedef void (gus_sample_event_handler_t)(snd_seq_event_t *ev, snd_gus_port_t *p, snd_gus_voice_t *v);
121
122static gus_sample_event_handler_t *gus_sample_event_handlers[9] = {
123 event_sample,
124 event_cluster,
125 event_start,
126 event_stop,
127 event_freq,
128 event_volume,
129 event_loop,
130 event_position,
131 event_private1
132};
133
134void snd_gus_sample_event(snd_seq_event_t *ev, snd_gus_port_t *p)
135{
136 int idx, voice;
137 snd_gus_card_t *gus = p->gus;
138 snd_gus_voice_t *v;
139 unsigned long flags;
140
141 idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
142 if (idx < 0 || idx > 8)
143 return;
144 for (voice = 0; voice < 32; voice++) {
145 v = &gus->gf1.voices[voice];
146 if (v->use && v->client == ev->source.client &&
147 v->port == ev->source.port &&
148 v->index == ev->data.sample.channel) {
149 spin_lock_irqsave(&gus->event_lock, flags);
150 gus_sample_event_handlers[idx](ev, p, v);
151 spin_unlock_irqrestore(&gus->event_lock, flags);
152 return;
153 }
154 }
155}
diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c
new file mode 100644
index 000000000000..c122e7be6ceb
--- /dev/null
+++ b/sound/isa/gus/gus_simple.c
@@ -0,0 +1,634 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Simple instrument handlers
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/time.h>
24#include <sound/core.h>
25#include <sound/gus.h>
26#include "gus_tables.h"
27
28/*
29 *
30 */
31
32static void interrupt_wave(snd_gus_card_t *gus, snd_gus_voice_t *voice);
33static void interrupt_volume(snd_gus_card_t *gus, snd_gus_voice_t *voice);
34static void interrupt_effect(snd_gus_card_t *gus, snd_gus_voice_t *voice);
35
36static void sample_start(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_position_t position);
37static void sample_stop(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_stop_mode_t mode);
38static void sample_freq(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_frequency_t freq);
39static void sample_volume(snd_gus_card_t *card, snd_gus_voice_t *voice, snd_seq_ev_volume_t *volume);
40static void sample_loop(snd_gus_card_t *card, snd_gus_voice_t *voice, snd_seq_ev_loop_t *loop);
41static void sample_pos(snd_gus_card_t *card, snd_gus_voice_t *voice, snd_seq_position_t position);
42static void sample_private1(snd_gus_card_t *card, snd_gus_voice_t *voice, unsigned char *data);
43
44static snd_gus_sample_ops_t sample_ops = {
45 sample_start,
46 sample_stop,
47 sample_freq,
48 sample_volume,
49 sample_loop,
50 sample_pos,
51 sample_private1
52};
53
54#if 0
55
56static void note_stop(snd_gus_card_t *gus, snd_gus_voice_t *voice, int wait);
57static void note_wait(snd_gus_card_t *gus, snd_gus_voice_t *voice);
58static void note_off(snd_gus_card_t *gus, snd_gus_voice_t *voice);
59static void note_volume(snd_gus_card_t *card, snd_gus_voice_t *voice);
60static void note_pitchbend(snd_gus_card_t *card, snd_gus_voice_t *voice);
61static void note_vibrato(snd_gus_card_t *card, snd_gus_voice_t *voice);
62static void note_tremolo(snd_gus_card_t *card, snd_gus_voice_t *voice);
63
64static struct snd_gus_note_handlers note_commands = {
65 note_stop,
66 note_wait,
67 note_off,
68 note_volume,
69 note_pitchbend,
70 note_vibrato,
71 note_tremolo
72};
73
74static void chn_trigger_down(snd_gus_card_t *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority );
75static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note );
76static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 );
77
78static struct ULTRA_STRU_INSTRUMENT_CHANNEL_COMMANDS channel_commands = {
79 chn_trigger_down,
80 chn_trigger_up,
81 chn_control
82};
83
84#endif
85
86static void do_volume_envelope(snd_gus_card_t *card, snd_gus_voice_t *voice);
87static void do_pan_envelope(snd_gus_card_t *card, snd_gus_voice_t *voice);
88
89/*
90 *
91 */
92
93static void interrupt_wave(snd_gus_card_t *gus, snd_gus_voice_t *voice)
94{
95 spin_lock(&gus->event_lock);
96 snd_gf1_stop_voice(gus, voice->number);
97 spin_lock(&gus->reg_lock);
98 snd_gf1_select_voice(gus, voice->number);
99 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0);
100 spin_unlock(&gus->reg_lock);
101 voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
102 spin_unlock(&gus->event_lock);
103}
104
105static void interrupt_volume(snd_gus_card_t *gus, snd_gus_voice_t *voice)
106{
107 spin_lock(&gus->event_lock);
108 if (voice->flags & SNDRV_GF1_VFLG_RUNNING)
109 do_volume_envelope(gus, voice);
110 else
111 snd_gf1_stop_voice(gus, voice->number);
112 spin_unlock(&gus->event_lock);
113}
114
115static void interrupt_effect(snd_gus_card_t *gus, snd_gus_voice_t *voice)
116{
117 spin_lock(&gus->event_lock);
118 if ((voice->flags & (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) ==
119 (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1))
120 do_pan_envelope(gus, voice);
121 spin_unlock(&gus->event_lock);
122}
123
124/*
125 *
126 */
127
128static void do_volume_envelope(snd_gus_card_t *gus, snd_gus_voice_t *voice)
129{
130 unsigned short next, rate, old_volume;
131 int program_next_ramp;
132 unsigned long flags;
133
134 if (!gus->gf1.volume_ramp) {
135 spin_lock_irqsave(&gus->reg_lock, flags);
136 snd_gf1_select_voice(gus, voice->number);
137 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
138 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume);
139 printk("gf1_volume = 0x%x\n", voice->gf1_volume);
140 spin_unlock_irqrestore(&gus->reg_lock, flags);
141 return;
142 }
143 program_next_ramp = 0;
144 rate = next = 0;
145 while (1) {
146 program_next_ramp = 0;
147 rate = next = 0;
148 switch (voice->venv_state) {
149 case VENV_BEFORE:
150 voice->venv_state = VENV_ATTACK;
151 voice->venv_value_next = 0;
152 spin_lock_irqsave(&gus->reg_lock, flags);
153 snd_gf1_select_voice(gus, voice->number);
154 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
155 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
156 spin_unlock_irqrestore(&gus->reg_lock, flags);
157 break;
158 case VENV_ATTACK:
159 voice->venv_state = VENV_SUSTAIN;
160 program_next_ramp++;
161 next = 255;
162 rate = gus->gf1.volume_ramp;
163 break;
164 case VENV_SUSTAIN:
165 voice->venv_state = VENV_RELEASE;
166 spin_lock_irqsave(&gus->reg_lock, flags);
167 snd_gf1_select_voice(gus, voice->number);
168 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
169 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, ((int)voice->gf1_volume * (int)voice->venv_value_next) / 255);
170 spin_unlock_irqrestore(&gus->reg_lock, flags);
171 return;
172 case VENV_RELEASE:
173 voice->venv_state = VENV_DONE;
174 program_next_ramp++;
175 next = 0;
176 rate = gus->gf1.volume_ramp;
177 break;
178 case VENV_DONE:
179 snd_gf1_stop_voice(gus, voice->number);
180 voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
181 return;
182 case VENV_VOLUME:
183 program_next_ramp++;
184 next = voice->venv_value_next;
185 rate = gus->gf1.volume_ramp;
186 voice->venv_state = voice->venv_state_prev;
187 break;
188 }
189 voice->venv_value_next = next;
190 if (!program_next_ramp)
191 continue;
192 spin_lock_irqsave(&gus->reg_lock, flags);
193 snd_gf1_select_voice(gus, voice->number);
194 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
195 old_volume = snd_gf1_read16(gus, SNDRV_GF1_VW_VOLUME) >> 8;
196 if (!rate) {
197 spin_unlock_irqrestore(&gus->reg_lock, flags);
198 continue;
199 }
200 next = (((int)voice->gf1_volume * (int)next) / 255) >> 8;
201 if (old_volume < SNDRV_GF1_MIN_OFFSET)
202 old_volume = SNDRV_GF1_MIN_OFFSET;
203 if (next < SNDRV_GF1_MIN_OFFSET)
204 next = SNDRV_GF1_MIN_OFFSET;
205 if (next > SNDRV_GF1_MAX_OFFSET)
206 next = SNDRV_GF1_MAX_OFFSET;
207 if (old_volume == next) {
208 spin_unlock_irqrestore(&gus->reg_lock, flags);
209 continue;
210 }
211 voice->volume_control &= ~0xc3;
212 voice->volume_control |= 0x20;
213 if (old_volume > next) {
214 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, next);
215 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, old_volume);
216 voice->volume_control |= 0x40;
217 } else {
218 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, old_volume);
219 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, next);
220 }
221 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, rate);
222 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
223 if (!gus->gf1.enh_mode) {
224 snd_gf1_delay(gus);
225 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
226 }
227 spin_unlock_irqrestore(&gus->reg_lock, flags);
228 return;
229 }
230}
231
232static void do_pan_envelope(snd_gus_card_t *gus, snd_gus_voice_t *voice)
233{
234 unsigned long flags;
235 unsigned char old_pan;
236
237#if 0
238 snd_gf1_select_voice(gus, voice->number);
239 printk(" -%i- do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n",
240 voice->number,
241 voice->flags,
242 voice->gf1_pan,
243 snd_gf1_i_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f);
244#endif
245 if (gus->gf1.enh_mode) {
246 voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
247 return;
248 }
249 if (!gus->gf1.smooth_pan) {
250 spin_lock_irqsave(&gus->reg_lock, flags);
251 snd_gf1_select_voice(gus, voice->number);
252 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
253 spin_unlock_irqrestore(&gus->reg_lock, flags);
254 return;
255 }
256 if (!(voice->flags & SNDRV_GF1_VFLG_PAN)) /* before */
257 voice->flags |= SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN;
258 spin_lock_irqsave(&gus->reg_lock, flags);
259 snd_gf1_select_voice(gus, voice->number);
260 old_pan = snd_gf1_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f;
261 if (old_pan > voice->gf1_pan )
262 old_pan--;
263 if (old_pan < voice->gf1_pan)
264 old_pan++;
265 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, old_pan);
266 spin_unlock_irqrestore(&gus->reg_lock, flags);
267 if (old_pan == voice->gf1_pan) /* the goal was reached */
268 voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
269#if 0
270 snd_gf1_select_voice(gus, voice->number);
271 printk(" -%i- (1) do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n",
272 voice->number,
273 voice->flags,
274 voice->gf1_pan,
275 snd_gf1_i_read8(gus, GF1_VB_PAN) & 0x0f);
276#endif
277}
278
279static void set_enhanced_pan(snd_gus_card_t *gus, snd_gus_voice_t *voice, unsigned short pan)
280{
281 unsigned long flags;
282 unsigned short vlo, vro;
283
284 vlo = SNDRV_GF1_ATTEN((SNDRV_GF1_ATTEN_TABLE_SIZE-1) - pan);
285 vro = SNDRV_GF1_ATTEN(pan);
286 if (pan != SNDRV_GF1_ATTEN_TABLE_SIZE - 1 && pan != 0) {
287 vlo >>= 1;
288 vro >>= 1;
289 }
290 vlo <<= 4;
291 vro <<= 4;
292#if 0
293 printk("vlo = 0x%x (0x%x), vro = 0x%x (0x%x)\n",
294 vlo, snd_gf1_i_read16(gus, GF1_VW_OFFSET_LEFT),
295 vro, snd_gf1_i_read16(gus, GF1_VW_OFFSET_RIGHT));
296#endif
297 spin_lock_irqsave(&gus->reg_lock, flags);
298 snd_gf1_select_voice(gus, voice->number);
299 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, vlo);
300 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, vro);
301 spin_unlock_irqrestore(&gus->reg_lock, flags);
302 voice->vlo = vlo;
303 voice->vro = vro;
304}
305
306/*
307 *
308 */
309
310static void sample_start(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_position_t position)
311{
312 unsigned long flags;
313 unsigned int begin, addr, addr_end, addr_start;
314 int w_16;
315 simple_instrument_t *simple;
316 snd_seq_kinstr_t *instr;
317
318 instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
319 if (instr == NULL)
320 return;
321 voice->instr = instr->instr; /* copy ID to speedup aliases */
322 simple = KINSTR_DATA(instr);
323 begin = simple->address.memory << 4;
324 w_16 = simple->format & SIMPLE_WAVE_16BIT ? 0x04 : 0;
325 addr_start = simple->loop_start;
326 if (simple->format & SIMPLE_WAVE_LOOP) {
327 addr_end = simple->loop_end;
328 } else {
329 addr_end = (simple->size << 4) - (w_16 ? 40 : 24);
330 }
331 if (simple->format & SIMPLE_WAVE_BACKWARD) {
332 addr = simple->loop_end;
333 if (position < simple->loop_end)
334 addr -= position;
335 } else {
336 addr = position;
337 }
338 voice->control = 0x00;
339 voice->mode = 0x20; /* enable offset registers */
340 if (simple->format & SIMPLE_WAVE_16BIT)
341 voice->control |= 0x04;
342 if (simple->format & SIMPLE_WAVE_BACKWARD)
343 voice->control |= 0x40;
344 if (simple->format & SIMPLE_WAVE_LOOP) {
345 voice->control |= 0x08;
346 } else {
347 voice->control |= 0x20;
348 }
349 if (simple->format & SIMPLE_WAVE_BIDIR)
350 voice->control |= 0x10;
351 if (simple->format & SIMPLE_WAVE_ULAW)
352 voice->mode |= 0x40;
353 if (w_16) {
354 addr = ((addr << 1) & ~0x1f) | (addr & 0x0f);
355 addr_start = ((addr_start << 1) & ~0x1f) | (addr_start & 0x0f);
356 addr_end = ((addr_end << 1) & ~0x1f) | (addr_end & 0x0f);
357 }
358 addr += begin;
359 addr_start += begin;
360 addr_end += begin;
361 snd_gf1_stop_voice(gus, voice->number);
362 spin_lock_irqsave(&gus->reg_lock, flags);
363 snd_gf1_select_voice(gus, voice->number);
364 snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
365 voice->venv_state = VENV_BEFORE;
366 voice->volume_control = 0x03;
367 snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
368 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
369 snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
370 if (!gus->gf1.enh_mode) {
371 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
372 } else {
373 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT, voice->vlo);
374 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, voice->vlo);
375 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT, voice->vro);
376 snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, voice->vro);
377 snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, voice->effect_accumulator);
378 snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, voice->gf1_effect_volume);
379 snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, voice->gf1_effect_volume);
380 }
381 spin_unlock_irqrestore(&gus->reg_lock, flags);
382 do_volume_envelope(gus, voice);
383 spin_lock_irqsave(&gus->reg_lock, flags);
384 snd_gf1_select_voice(gus, voice->number);
385 if (gus->gf1.enh_mode)
386 snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, voice->mode);
387 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control);
388 if (!gus->gf1.enh_mode) {
389 snd_gf1_delay(gus);
390 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control );
391 }
392 spin_unlock_irqrestore(&gus->reg_lock, flags);
393#if 0
394 snd_gf1_print_voice_registers(gus);
395#endif
396 voice->flags |= SNDRV_GF1_VFLG_RUNNING;
397 snd_seq_instr_free_use(gus->gf1.ilist, instr);
398}
399
400static void sample_stop(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_stop_mode_t mode)
401{
402 unsigned char control;
403 unsigned long flags;
404
405 if (!(voice->flags & SNDRV_GF1_VFLG_RUNNING))
406 return;
407 switch (mode) {
408 default:
409 if (gus->gf1.volume_ramp > 0) {
410 if (voice->venv_state < VENV_RELEASE) {
411 voice->venv_state = VENV_RELEASE;
412 do_volume_envelope(gus, voice);
413 }
414 }
415 if (mode != SAMPLE_STOP_VENVELOPE) {
416 snd_gf1_stop_voice(gus, voice->number);
417 spin_lock_irqsave(&gus->reg_lock, flags);
418 snd_gf1_select_voice(gus, voice->number);
419 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
420 spin_unlock_irqrestore(&gus->reg_lock, flags);
421 voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
422 }
423 break;
424 case SAMPLE_STOP_LOOP: /* disable loop only */
425 spin_lock_irqsave(&gus->reg_lock, flags);
426 snd_gf1_select_voice(gus, voice->number);
427 control = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
428 control &= ~(0x83 | 0x04);
429 control |= 0x20;
430 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, control);
431 spin_unlock_irqrestore(&gus->reg_lock, flags);
432 break;
433 }
434}
435
436static void sample_freq(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_frequency_t freq)
437{
438 unsigned long flags;
439
440 spin_lock_irqsave(&gus->reg_lock, flags);
441 voice->fc_register = snd_gf1_translate_freq(gus, freq);
442 snd_gf1_select_voice(gus, voice->number);
443 snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
444 spin_unlock_irqrestore(&gus->reg_lock, flags);
445}
446
447static void sample_volume(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_ev_volume_t *volume)
448{
449 if (volume->volume >= 0) {
450 volume->volume &= 0x3fff;
451 voice->gf1_volume = snd_gf1_lvol_to_gvol_raw(volume->volume << 2) << 4;
452 voice->venv_state_prev = VENV_SUSTAIN;
453 voice->venv_state = VENV_VOLUME;
454 do_volume_envelope(gus, voice);
455 }
456 if (volume->lr >= 0) {
457 volume->lr &= 0x3fff;
458 if (!gus->gf1.enh_mode) {
459 voice->gf1_pan = (volume->lr >> 10) & 15;
460 if (!gus->gf1.full_range_pan) {
461 if (voice->gf1_pan == 0)
462 voice->gf1_pan++;
463 if (voice->gf1_pan == 15)
464 voice->gf1_pan--;
465 }
466 voice->flags &= ~SNDRV_GF1_VFLG_PAN; /* before */
467 do_pan_envelope(gus, voice);
468 } else {
469 set_enhanced_pan(gus, voice, volume->lr >> 7);
470 }
471 }
472}
473
474static void sample_loop(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_ev_loop_t *loop)
475{
476 unsigned long flags;
477 int w_16 = voice->control & 0x04;
478 unsigned int begin, addr_start, addr_end;
479 simple_instrument_t *simple;
480 snd_seq_kinstr_t *instr;
481
482#if 0
483 printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end);
484#endif
485 instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
486 if (instr == NULL)
487 return;
488 voice->instr = instr->instr; /* copy ID to speedup aliases */
489 simple = KINSTR_DATA(instr);
490 begin = simple->address.memory;
491 addr_start = loop->start;
492 addr_end = loop->end;
493 addr_start = (((addr_start << 1) & ~0x1f) | (addr_start & 0x0f)) + begin;
494 addr_end = (((addr_end << 1) & ~0x1f) | (addr_end & 0x0f)) + begin;
495 spin_lock_irqsave(&gus->reg_lock, flags);
496 snd_gf1_select_voice(gus, voice->number);
497 snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
498 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
499 spin_unlock_irqrestore(&gus->reg_lock, flags);
500 snd_seq_instr_free_use(gus->gf1.ilist, instr);
501}
502
503static void sample_pos(snd_gus_card_t *gus, snd_gus_voice_t *voice, snd_seq_position_t position)
504{
505 unsigned long flags;
506 int w_16 = voice->control & 0x04;
507 unsigned int begin, addr;
508 simple_instrument_t *simple;
509 snd_seq_kinstr_t *instr;
510
511#if 0
512 printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end);
513#endif
514 instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
515 if (instr == NULL)
516 return;
517 voice->instr = instr->instr; /* copy ID to speedup aliases */
518 simple = KINSTR_DATA(instr);
519 begin = simple->address.memory;
520 addr = (((position << 1) & ~0x1f) | (position & 0x0f)) + begin;
521 spin_lock_irqsave(&gus->reg_lock, flags);
522 snd_gf1_select_voice(gus, voice->number);
523 snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
524 spin_unlock_irqrestore(&gus->reg_lock, flags);
525 snd_seq_instr_free_use(gus->gf1.ilist, instr);
526}
527
528#if 0
529
530static unsigned char get_effects_mask( ultra_card_t *card, int value )
531{
532 if ( value > 7 ) return 0;
533 if ( card -> gf1.effects && card -> gf1.effects -> chip_type == ULTRA_EFFECT_CHIP_INTERWAVE )
534 return card -> gf1.effects -> chip.interwave.voice_output[ value ];
535 return 0;
536}
537
538#endif
539
540static void sample_private1(snd_gus_card_t *card, snd_gus_voice_t *voice, unsigned char *data)
541{
542#if 0
543 unsigned long flags;
544 unsigned char uc;
545
546 switch ( *data ) {
547 case ULTRA_PRIV1_IW_EFFECT:
548 uc = get_effects_mask( card, ultra_get_byte( data, 4 ) );
549 uc |= get_effects_mask( card, ultra_get_byte( data, 4 ) >> 4 );
550 uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) );
551 uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) >> 4 );
552 voice -> data.simple.effect_accumulator = uc;
553 voice -> data.simple.effect_volume = ultra_translate_voice_volume( card, ultra_get_word( data, 2 ) ) << 4;
554 if ( !card -> gf1.enh_mode ) return;
555 if ( voice -> flags & VFLG_WAIT_FOR_START ) return;
556 if ( voice -> flags & VFLG_RUNNING )
557 {
558 CLI( &flags );
559 gf1_select_voice( card, voice -> number );
560 ultra_write8( card, GF1_VB_ACCUMULATOR, voice -> data.simple.effect_accumulator );
561 ultra_write16( card, GF1_VW_EFFECT_VOLUME_FINAL, voice -> data.simple.effect_volume );
562 STI( &flags );
563 }
564 break;
565 case ULTRA_PRIV1_IW_LFO:
566 ultra_lfo_command( card, voice -> number, data );
567 }
568#endif
569}
570
571#if 0
572
573/*
574 *
575 */
576
577static void note_stop( ultra_card_t *card, ultra_voice_t *voice, int wait )
578{
579}
580
581static void note_wait( ultra_card_t *card, ultra_voice_t *voice )
582{
583}
584
585static void note_off( ultra_card_t *card, ultra_voice_t *voice )
586{
587}
588
589static void note_volume( ultra_card_t *card, ultra_voice_t *voice )
590{
591}
592
593static void note_pitchbend( ultra_card_t *card, ultra_voice_t *voice )
594{
595}
596
597static void note_vibrato( ultra_card_t *card, ultra_voice_t *voice )
598{
599}
600
601static void note_tremolo( ultra_card_t *card, ultra_voice_t *voice )
602{
603}
604
605/*
606 *
607 */
608
609static void chn_trigger_down( ultra_card_t *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority )
610{
611}
612
613static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note )
614{
615}
616
617static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 )
618{
619}
620
621/*
622 *
623 */
624
625#endif
626
627void snd_gf1_simple_init(snd_gus_voice_t *voice)
628{
629 voice->handler_wave = interrupt_wave;
630 voice->handler_volume = interrupt_volume;
631 voice->handler_effect = interrupt_effect;
632 voice->volume_change = NULL;
633 voice->sample_ops = &sample_ops;
634}
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c
new file mode 100644
index 000000000000..66552e6013a4
--- /dev/null
+++ b/sound/isa/gus/gus_synth.c
@@ -0,0 +1,329 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Synthesizer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/init.h>
24#include <linux/time.h>
25#include <sound/core.h>
26#include <sound/gus.h>
27#include <sound/seq_device.h>
28
29MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
30MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer");
31MODULE_LICENSE("GPL");
32
33/*
34 *
35 */
36
37static void snd_gus_synth_free_voices(snd_gus_card_t * gus, int client, int port)
38{
39 int idx;
40 snd_gus_voice_t * voice;
41
42 for (idx = 0; idx < 32; idx++) {
43 voice = &gus->gf1.voices[idx];
44 if (voice->use && voice->client == client && voice->port == port)
45 snd_gf1_free_voice(gus, voice);
46 }
47}
48
49static int snd_gus_synth_use(void *private_data, snd_seq_port_subscribe_t *info)
50{
51 snd_gus_port_t * port = (snd_gus_port_t *)private_data;
52 snd_gus_card_t * gus = port->gus;
53 snd_gus_voice_t * voice;
54 unsigned int idx;
55
56 if (info->voices > 32)
57 return -EINVAL;
58 down(&gus->register_mutex);
59 if (!snd_gus_use_inc(gus)) {
60 up(&gus->register_mutex);
61 return -EFAULT;
62 }
63 for (idx = 0; idx < info->voices; idx++) {
64 voice = snd_gf1_alloc_voice(gus, SNDRV_GF1_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port);
65 if (voice == NULL) {
66 snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
67 snd_gus_use_dec(gus);
68 up(&gus->register_mutex);
69 return -EBUSY;
70 }
71 voice->index = idx;
72 }
73 up(&gus->register_mutex);
74 return 0;
75}
76
77static int snd_gus_synth_unuse(void *private_data, snd_seq_port_subscribe_t *info)
78{
79 snd_gus_port_t * port = (snd_gus_port_t *)private_data;
80 snd_gus_card_t * gus = port->gus;
81
82 down(&gus->register_mutex);
83 snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
84 snd_gus_use_dec(gus);
85 up(&gus->register_mutex);
86 return 0;
87}
88
89/*
90 *
91 */
92
93static void snd_gus_synth_free_private_instruments(snd_gus_port_t *p, int client)
94{
95 snd_seq_instr_header_t ifree;
96
97 memset(&ifree, 0, sizeof(ifree));
98 ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE;
99 snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0);
100}
101
102int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop)
103{
104 snd_gus_port_t * p = (snd_gus_port_t *) private_data;
105
106 snd_assert(p != NULL, return -EINVAL);
107 if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
108 ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
109 snd_gus_sample_event(ev, p);
110 return 0;
111 }
112 if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
113 ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
114 if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
115 snd_gus_synth_free_private_instruments(p, ev->data.addr.client);
116 return 0;
117 }
118 }
119 if (direct) {
120 if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
121 snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops,
122 p->gus->gf1.ilist,
123 ev,
124 p->gus->gf1.seq_client,
125 atomic, hop);
126 return 0;
127 }
128 }
129 return 0;
130}
131
132static void snd_gus_synth_instr_notify(void *private_data,
133 snd_seq_kinstr_t *instr,
134 int what)
135{
136 unsigned int idx;
137 snd_gus_card_t *gus = private_data;
138 snd_gus_voice_t *pvoice;
139 unsigned long flags;
140
141 spin_lock_irqsave(&gus->event_lock, flags);
142 for (idx = 0; idx < 32; idx++) {
143 pvoice = &gus->gf1.voices[idx];
144 if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
145 if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
146 pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY);
147 } else {
148 snd_gf1_stop_voice(gus, pvoice->number);
149 pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
150 }
151 }
152 }
153 spin_unlock_irqrestore(&gus->event_lock, flags);
154}
155
156/*
157 *
158 */
159
160static void snd_gus_synth_free_port(void *private_data)
161{
162 snd_gus_port_t * p = (snd_gus_port_t *)private_data;
163
164 if (p)
165 snd_midi_channel_free_set(p->chset);
166}
167
168static int snd_gus_synth_create_port(snd_gus_card_t * gus, int idx)
169{
170 snd_gus_port_t * p;
171 snd_seq_port_callback_t callbacks;
172 char name[32];
173 int result;
174
175 p = &gus->gf1.seq_ports[idx];
176 p->chset = snd_midi_channel_alloc_set(16);
177 if (p->chset == NULL)
178 return -ENOMEM;
179 p->chset->private_data = p;
180 p->gus = gus;
181 p->client = gus->gf1.seq_client;
182
183 memset(&callbacks, 0, sizeof(callbacks));
184 callbacks.owner = THIS_MODULE;
185 callbacks.use = snd_gus_synth_use;
186 callbacks.unuse = snd_gus_synth_unuse;
187 callbacks.event_input = snd_gus_synth_event_input;
188 callbacks.private_free = snd_gus_synth_free_port;
189 callbacks.private_data = p;
190
191 sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx);
192 p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client,
193 &callbacks,
194 SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
195 SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
196 SNDRV_SEQ_PORT_TYPE_SYNTH,
197 16, 0,
198 name);
199 if (p->chset->port < 0) {
200 result = p->chset->port;
201 snd_gus_synth_free_port(p);
202 return result;
203 }
204 p->port = p->chset->port;
205 return 0;
206}
207
208/*
209 *
210 */
211
212static int snd_gus_synth_new_device(snd_seq_device_t *dev)
213{
214 snd_gus_card_t *gus;
215 int client, i;
216 snd_seq_client_callback_t callbacks;
217 snd_seq_client_info_t *cinfo;
218 snd_seq_port_subscribe_t sub;
219 snd_iwffff_ops_t *iwops;
220 snd_gf1_ops_t *gf1ops;
221 snd_simple_ops_t *simpleops;
222
223 gus = *(snd_gus_card_t**)SNDRV_SEQ_DEVICE_ARGPTR(dev);
224 if (gus == NULL)
225 return -EINVAL;
226
227 init_MUTEX(&gus->register_mutex);
228 gus->gf1.seq_client = -1;
229
230 cinfo = kmalloc(sizeof(*cinfo), GFP_KERNEL);
231 if (! cinfo)
232 return -ENOMEM;
233
234 /* allocate new client */
235 memset(&callbacks, 0, sizeof(callbacks));
236 callbacks.private_data = gus;
237 callbacks.allow_output = callbacks.allow_input = 1;
238 client = gus->gf1.seq_client =
239 snd_seq_create_kernel_client(gus->card, 1, &callbacks);
240 if (client < 0) {
241 kfree(cinfo);
242 return client;
243 }
244
245 /* change name of client */
246 memset(cinfo, 0, sizeof(*cinfo));
247 cinfo->client = client;
248 cinfo->type = KERNEL_CLIENT;
249 sprintf(cinfo->name, gus->interwave ? "AMD InterWave" : "GF1");
250 snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, cinfo);
251 kfree(cinfo);
252
253 for (i = 0; i < 4; i++)
254 snd_gus_synth_create_port(gus, i);
255
256 gus->gf1.ilist = snd_seq_instr_list_new();
257 if (gus->gf1.ilist == NULL) {
258 snd_seq_delete_kernel_client(client);
259 gus->gf1.seq_client = -1;
260 return -ENOMEM;
261 }
262 gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
263
264 simpleops = &gus->gf1.simple_ops;
265 snd_seq_simple_init(simpleops, gus, NULL);
266 simpleops->put_sample = snd_gus_simple_put_sample;
267 simpleops->get_sample = snd_gus_simple_get_sample;
268 simpleops->remove_sample = snd_gus_simple_remove_sample;
269 simpleops->notify = snd_gus_synth_instr_notify;
270
271 gf1ops = &gus->gf1.gf1_ops;
272 snd_seq_gf1_init(gf1ops, gus, &simpleops->kops);
273 gf1ops->put_sample = snd_gus_gf1_put_sample;
274 gf1ops->get_sample = snd_gus_gf1_get_sample;
275 gf1ops->remove_sample = snd_gus_gf1_remove_sample;
276 gf1ops->notify = snd_gus_synth_instr_notify;
277
278 iwops = &gus->gf1.iwffff_ops;
279 snd_seq_iwffff_init(iwops, gus, &gf1ops->kops);
280 iwops->put_sample = snd_gus_iwffff_put_sample;
281 iwops->get_sample = snd_gus_iwffff_get_sample;
282 iwops->remove_sample = snd_gus_iwffff_remove_sample;
283 iwops->notify = snd_gus_synth_instr_notify;
284
285 memset(&sub, 0, sizeof(sub));
286 sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
287 sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
288 sub.dest.client = client;
289 sub.dest.port = 0;
290 snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
291
292 return 0;
293}
294
295static int snd_gus_synth_delete_device(snd_seq_device_t *dev)
296{
297 snd_gus_card_t *gus;
298
299 gus = *(snd_gus_card_t**)SNDRV_SEQ_DEVICE_ARGPTR(dev);
300 if (gus == NULL)
301 return -EINVAL;
302
303 if (gus->gf1.seq_client >= 0) {
304 snd_seq_delete_kernel_client(gus->gf1.seq_client);
305 gus->gf1.seq_client = -1;
306 }
307 if (gus->gf1.ilist)
308 snd_seq_instr_list_free(&gus->gf1.ilist);
309 return 0;
310}
311
312static int __init alsa_gus_synth_init(void)
313{
314 static snd_seq_dev_ops_t ops = {
315 snd_gus_synth_new_device,
316 snd_gus_synth_delete_device
317 };
318
319 return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops,
320 sizeof(snd_gus_card_t*));
321}
322
323static void __exit alsa_gus_synth_exit(void)
324{
325 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS);
326}
327
328module_init(alsa_gus_synth_init)
329module_exit(alsa_gus_synth_exit)
diff --git a/sound/isa/gus/gus_tables.h b/sound/isa/gus/gus_tables.h
new file mode 100644
index 000000000000..ed8e9d85ad31
--- /dev/null
+++ b/sound/isa/gus/gus_tables.h
@@ -0,0 +1,86 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 *
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#define SNDRV_GF1_SCALE_TABLE_SIZE 128
22#define SNDRV_GF1_ATTEN_TABLE_SIZE 128
23
24#ifdef __GUS_TABLES_ALLOC__
25
26unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] =
27{
28 8372, 8870, 9397, 9956, 10548, 11175,
29 11840, 12544, 13290, 14080, 14917, 15804,
30 16744, 17740, 18795, 19912, 21096, 22351,
31 23680, 25088, 26580, 28160, 29834, 31609,
32 33488, 35479, 37589, 39824, 42192, 44701,
33 47359, 50175, 53159, 56320, 59669, 63217,
34 66976, 70959, 75178, 79649, 84385, 89402,
35 94719, 100351, 106318, 112640, 119338, 126434,
36 133952, 141918, 150356, 159297, 168769, 178805,
37 189437, 200702, 212636, 225280, 238676, 252868,
38 267905, 283835, 300713, 318594, 337539, 357610,
39 378874, 401403, 425272, 450560, 477352, 505737,
40 535809, 567670, 601425, 637188, 675077, 715219,
41 757749, 802807, 850544, 901120, 954703, 1011473,
42 1071618, 1135340, 1202851, 1274376, 1350154, 1430439,
43 1515497, 1605613, 1701088, 1802240, 1909407, 2022946,
44 2143237, 2270680, 2405702, 2548752, 2700309, 2860878,
45 3030994, 3211227, 3402176, 3604480, 3818814, 4045892,
46 4286473, 4541360, 4811404, 5097505, 5400618, 5721755,
47 6061989, 6422453, 6804352, 7208960, 7637627, 8091784,
48 8572947, 9082720, 9622807, 10195009, 10801236, 11443511,
49 12123977, 12844906
50};
51
52unsigned short snd_gf1_atten_table[SNDRV_GF1_ATTEN_TABLE_SIZE] = {
53 4095 /* 0 */,1789 /* 1 */,1533 /* 2 */,1383 /* 3 */,1277 /* 4 */,
54 1195 /* 5 */,1127 /* 6 */,1070 /* 7 */,1021 /* 8 */,978 /* 9 */,
55 939 /* 10 */,903 /* 11 */,871 /* 12 */,842 /* 13 */,814 /* 14 */,
56 789 /* 15 */,765 /* 16 */,743 /* 17 */,722 /* 18 */,702 /* 19 */,
57 683 /* 20 */,665 /* 21 */,647 /* 22 */,631 /* 23 */,615 /* 24 */,
58 600 /* 25 */,586 /* 26 */,572 /* 27 */,558 /* 28 */,545 /* 29 */,
59 533 /* 30 */,521 /* 31 */,509 /* 32 */,498 /* 33 */,487 /* 34 */,
60 476 /* 35 */,466 /* 36 */,455 /* 37 */,446 /* 38 */,436 /* 39 */,
61 427 /* 40 */,418 /* 41 */,409 /* 42 */,400 /* 43 */,391 /* 44 */,
62 383 /* 45 */,375 /* 46 */,367 /* 47 */,359 /* 48 */,352 /* 49 */,
63 344 /* 50 */,337 /* 51 */,330 /* 52 */,323 /* 53 */,316 /* 54 */,
64 309 /* 55 */,302 /* 56 */,296 /* 57 */,289 /* 58 */,283 /* 59 */,
65 277 /* 60 */,271 /* 61 */,265 /* 62 */,259 /* 63 */,253 /* 64 */,
66 247 /* 65 */,242 /* 66 */,236 /* 67 */,231 /* 68 */,225 /* 69 */,
67 220 /* 70 */,215 /* 71 */,210 /* 72 */,205 /* 73 */,199 /* 74 */,
68 195 /* 75 */,190 /* 76 */,185 /* 77 */,180 /* 78 */,175 /* 79 */,
69 171 /* 80 */,166 /* 81 */,162 /* 82 */,157 /* 83 */,153 /* 84 */,
70 148 /* 85 */,144 /* 86 */,140 /* 87 */,135 /* 88 */,131 /* 89 */,
71 127 /* 90 */,123 /* 91 */,119 /* 92 */,115 /* 93 */,111 /* 94 */,
72 107 /* 95 */,103 /* 96 */,100 /* 97 */,96 /* 98 */,92 /* 99 */,
73 88 /* 100 */,85 /* 101 */,81 /* 102 */,77 /* 103 */,74 /* 104 */,
74 70 /* 105 */,67 /* 106 */,63 /* 107 */,60 /* 108 */,56 /* 109 */,
75 53 /* 110 */,50 /* 111 */,46 /* 112 */,43 /* 113 */,40 /* 114 */,
76 37 /* 115 */,33 /* 116 */,30 /* 117 */,27 /* 118 */,24 /* 119 */,
77 21 /* 120 */,18 /* 121 */,15 /* 122 */,12 /* 123 */,9 /* 124 */,
78 6 /* 125 */,3 /* 126 */,0 /* 127 */,
79};
80
81#else
82
83extern unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE];
84extern unsigned short snd_gf1_atten_table[SNDRV_GF1_ATTEN_TABLE_SIZE];
85
86#endif
diff --git a/sound/isa/gus/gus_timer.c b/sound/isa/gus/gus_timer.c
new file mode 100644
index 000000000000..9876603ff6c1
--- /dev/null
+++ b/sound/isa/gus/gus_timer.c
@@ -0,0 +1,204 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Timers
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 * GUS have similar timers as AdLib (OPL2/OPL3 chips).
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sound/driver.h>
25#include <linux/time.h>
26#include <sound/core.h>
27#include <sound/gus.h>
28
29/*
30 * Timer 1 - 80us
31 */
32
33static int snd_gf1_timer1_start(snd_timer_t * timer)
34{
35 unsigned long flags;
36 unsigned char tmp;
37 unsigned int ticks;
38 snd_gus_card_t *gus;
39
40 gus = snd_timer_chip(timer);
41 spin_lock_irqsave(&gus->reg_lock, flags);
42 ticks = timer->sticks;
43 tmp = (gus->gf1.timer_enabled |= 4);
44 snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1, 256 - ticks); /* timer 1 count */
45 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 1 IRQ */
46 snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */
47 spin_unlock_irqrestore(&gus->reg_lock, flags);
48 return 0;
49}
50
51static int snd_gf1_timer1_stop(snd_timer_t * timer)
52{
53 unsigned long flags;
54 unsigned char tmp;
55 snd_gus_card_t *gus;
56
57 gus = snd_timer_chip(timer);
58 spin_lock_irqsave(&gus->reg_lock, flags);
59 tmp = (gus->gf1.timer_enabled &= ~4);
60 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */
61 spin_unlock_irqrestore(&gus->reg_lock, flags);
62 return 0;
63}
64
65/*
66 * Timer 2 - 320us
67 */
68
69static int snd_gf1_timer2_start(snd_timer_t * timer)
70{
71 unsigned long flags;
72 unsigned char tmp;
73 unsigned int ticks;
74 snd_gus_card_t *gus;
75
76 gus = snd_timer_chip(timer);
77 spin_lock_irqsave(&gus->reg_lock, flags);
78 ticks = timer->sticks;
79 tmp = (gus->gf1.timer_enabled |= 8);
80 snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks); /* timer 2 count */
81 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 2 IRQ */
82 snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */
83 spin_unlock_irqrestore(&gus->reg_lock, flags);
84 return 0;
85}
86
87static int snd_gf1_timer2_stop(snd_timer_t * timer)
88{
89 unsigned long flags;
90 unsigned char tmp;
91 snd_gus_card_t *gus;
92
93 gus = snd_timer_chip(timer);
94 spin_lock_irqsave(&gus->reg_lock, flags);
95 tmp = (gus->gf1.timer_enabled &= ~8);
96 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */
97 spin_unlock_irqrestore(&gus->reg_lock, flags);
98 return 0;
99}
100
101/*
102
103 */
104
105static void snd_gf1_interrupt_timer1(snd_gus_card_t * gus)
106{
107 snd_timer_t *timer = gus->gf1.timer1;
108
109 if (timer == NULL)
110 return;
111 snd_timer_interrupt(timer, timer->sticks);
112}
113
114static void snd_gf1_interrupt_timer2(snd_gus_card_t * gus)
115{
116 snd_timer_t *timer = gus->gf1.timer2;
117
118 if (timer == NULL)
119 return;
120 snd_timer_interrupt(timer, timer->sticks);
121}
122
123/*
124
125 */
126
127static struct _snd_timer_hardware snd_gf1_timer1 =
128{
129 .flags = SNDRV_TIMER_HW_STOP,
130 .resolution = 80000,
131 .ticks = 256,
132 .start = snd_gf1_timer1_start,
133 .stop = snd_gf1_timer1_stop,
134};
135
136static struct _snd_timer_hardware snd_gf1_timer2 =
137{
138 .flags = SNDRV_TIMER_HW_STOP,
139 .resolution = 320000,
140 .ticks = 256,
141 .start = snd_gf1_timer2_start,
142 .stop = snd_gf1_timer2_stop,
143};
144
145static void snd_gf1_timer1_free(snd_timer_t *timer)
146{
147 snd_gus_card_t *gus = timer->private_data;
148 gus->gf1.timer1 = NULL;
149}
150
151static void snd_gf1_timer2_free(snd_timer_t *timer)
152{
153 snd_gus_card_t *gus = timer->private_data;
154 gus->gf1.timer2 = NULL;
155}
156
157void snd_gf1_timers_init(snd_gus_card_t * gus)
158{
159 snd_timer_t *timer;
160 snd_timer_id_t tid;
161
162 if (gus->gf1.timer1 != NULL || gus->gf1.timer2 != NULL)
163 return;
164
165 gus->gf1.interrupt_handler_timer1 = snd_gf1_interrupt_timer1;
166 gus->gf1.interrupt_handler_timer2 = snd_gf1_interrupt_timer2;
167
168 tid.dev_class = SNDRV_TIMER_CLASS_CARD;
169 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
170 tid.card = gus->card->number;
171 tid.device = gus->timer_dev;
172 tid.subdevice = 0;
173
174 if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
175 strcpy(timer->name, "GF1 timer #1");
176 timer->private_data = gus;
177 timer->private_free = snd_gf1_timer1_free;
178 timer->hw = snd_gf1_timer1;
179 }
180 gus->gf1.timer1 = timer;
181
182 tid.device++;
183
184 if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
185 strcpy(timer->name, "GF1 timer #2");
186 timer->private_data = gus;
187 timer->private_free = snd_gf1_timer2_free;
188 timer->hw = snd_gf1_timer2;
189 }
190 gus->gf1.timer2 = timer;
191}
192
193void snd_gf1_timers_done(snd_gus_card_t * gus)
194{
195 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_TIMER1 | SNDRV_GF1_HANDLER_TIMER2);
196 if (gus->gf1.timer1) {
197 snd_device_free(gus->card, gus->gf1.timer1);
198 gus->gf1.timer1 = NULL;
199 }
200 if (gus->gf1.timer2) {
201 snd_device_free(gus->card, gus->gf1.timer2);
202 gus->gf1.timer2 = NULL;
203 }
204}
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
new file mode 100644
index 000000000000..1bc2da8784e0
--- /dev/null
+++ b/sound/isa/gus/gus_uart.c
@@ -0,0 +1,257 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for the GF1 MIDI interface - like UART 6850
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/delay.h>
24#include <linux/interrupt.h>
25#include <linux/time.h>
26#include <sound/core.h>
27#include <sound/gus.h>
28
29static void snd_gf1_interrupt_midi_in(snd_gus_card_t * gus)
30{
31 int count;
32 unsigned char stat, data, byte;
33 unsigned long flags;
34
35 count = 10;
36 while (count) {
37 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
38 stat = snd_gf1_uart_stat(gus);
39 if (!(stat & 0x01)) { /* data in Rx FIFO? */
40 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
41 count--;
42 continue;
43 }
44 count = 100; /* arm counter to new value */
45 data = snd_gf1_uart_get(gus);
46 if (!(gus->gf1.uart_cmd & 0x80)) {
47 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
48 continue;
49 }
50 if (stat & 0x10) { /* framing error */
51 gus->gf1.uart_framing++;
52 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
53 continue;
54 }
55 byte = snd_gf1_uart_get(gus);
56 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
57 snd_rawmidi_receive(gus->midi_substream_input, &byte, 1);
58 if (stat & 0x20) {
59 gus->gf1.uart_overrun++;
60 }
61 }
62}
63
64static void snd_gf1_interrupt_midi_out(snd_gus_card_t * gus)
65{
66 char byte;
67 unsigned long flags;
68
69 /* try unlock output */
70 if (snd_gf1_uart_stat(gus) & 0x01)
71 snd_gf1_interrupt_midi_in(gus);
72
73 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
74 if (snd_gf1_uart_stat(gus) & 0x02) { /* Tx FIFO free? */
75 if (snd_rawmidi_transmit(gus->midi_substream_output, &byte, 1) != 1) { /* no other bytes or error */
76 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20); /* disable Tx interrupt */
77 } else {
78 snd_gf1_uart_put(gus, byte);
79 }
80 }
81 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
82}
83
84static void snd_gf1_uart_reset(snd_gus_card_t * gus, int close)
85{
86 snd_gf1_uart_cmd(gus, 0x03); /* reset */
87 if (!close && gus->uart_enable) {
88 udelay(160);
89 snd_gf1_uart_cmd(gus, 0x00); /* normal operations */
90 }
91}
92
93static int snd_gf1_uart_output_open(snd_rawmidi_substream_t * substream)
94{
95 unsigned long flags;
96 snd_gus_card_t *gus;
97
98 gus = substream->rmidi->private_data;
99 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
100 if (!(gus->gf1.uart_cmd & 0x80)) { /* input active? */
101 snd_gf1_uart_reset(gus, 0);
102 }
103 gus->gf1.interrupt_handler_midi_out = snd_gf1_interrupt_midi_out;
104 gus->midi_substream_output = substream;
105 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
106#if 0
107 snd_printk("write init - cmd = 0x%x, stat = 0x%x\n", gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
108#endif
109 return 0;
110}
111
112static int snd_gf1_uart_input_open(snd_rawmidi_substream_t * substream)
113{
114 unsigned long flags;
115 snd_gus_card_t *gus;
116 int i;
117
118 gus = substream->rmidi->private_data;
119 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
120 if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) {
121 snd_gf1_uart_reset(gus, 0);
122 }
123 gus->gf1.interrupt_handler_midi_in = snd_gf1_interrupt_midi_in;
124 gus->midi_substream_input = substream;
125 if (gus->uart_enable) {
126 for (i = 0; i < 1000 && (snd_gf1_uart_stat(gus) & 0x01); i++)
127 snd_gf1_uart_get(gus); /* clean Rx */
128 if (i >= 1000)
129 snd_printk("gus midi uart init read - cleanup error\n");
130 }
131 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
132#if 0
133 snd_printk("read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
134 snd_printk("[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n", gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100), inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
135#endif
136 return 0;
137}
138
139static int snd_gf1_uart_output_close(snd_rawmidi_substream_t * substream)
140{
141 unsigned long flags;
142 snd_gus_card_t *gus;
143
144 gus = substream->rmidi->private_data;
145 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
146 if (gus->gf1.interrupt_handler_midi_in != snd_gf1_interrupt_midi_in)
147 snd_gf1_uart_reset(gus, 1);
148 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_OUT);
149 gus->midi_substream_output = NULL;
150 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
151 return 0;
152}
153
154static int snd_gf1_uart_input_close(snd_rawmidi_substream_t * substream)
155{
156 unsigned long flags;
157 snd_gus_card_t *gus;
158
159 gus = substream->rmidi->private_data;
160 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
161 if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out)
162 snd_gf1_uart_reset(gus, 1);
163 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_IN);
164 gus->midi_substream_input = NULL;
165 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
166 return 0;
167}
168
169static void snd_gf1_uart_input_trigger(snd_rawmidi_substream_t * substream, int up)
170{
171 snd_gus_card_t *gus;
172 unsigned long flags;
173
174 gus = substream->rmidi->private_data;
175
176 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
177 if (up) {
178 if ((gus->gf1.uart_cmd & 0x80) == 0)
179 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x80); /* enable Rx interrupts */
180 } else {
181 if (gus->gf1.uart_cmd & 0x80)
182 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x80); /* disable Rx interrupts */
183 }
184 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
185}
186
187static void snd_gf1_uart_output_trigger(snd_rawmidi_substream_t * substream, int up)
188{
189 unsigned long flags;
190 snd_gus_card_t *gus;
191 char byte;
192 int timeout;
193
194 gus = substream->rmidi->private_data;
195
196 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
197 if (up) {
198 if ((gus->gf1.uart_cmd & 0x20) == 0) {
199 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
200 /* wait for empty Rx - Tx is probably unlocked */
201 timeout = 10000;
202 while (timeout-- > 0 && snd_gf1_uart_stat(gus) & 0x01);
203 /* Tx FIFO free? */
204 spin_lock_irqsave(&gus->uart_cmd_lock, flags);
205 if (gus->gf1.uart_cmd & 0x20) {
206 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
207 return;
208 }
209 if (snd_gf1_uart_stat(gus) & 0x02) {
210 if (snd_rawmidi_transmit(substream, &byte, 1) != 1) {
211 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
212 return;
213 }
214 snd_gf1_uart_put(gus, byte);
215 }
216 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x20); /* enable Tx interrupt */
217 }
218 } else {
219 if (gus->gf1.uart_cmd & 0x20)
220 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20);
221 }
222 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
223}
224
225static snd_rawmidi_ops_t snd_gf1_uart_output =
226{
227 .open = snd_gf1_uart_output_open,
228 .close = snd_gf1_uart_output_close,
229 .trigger = snd_gf1_uart_output_trigger,
230};
231
232static snd_rawmidi_ops_t snd_gf1_uart_input =
233{
234 .open = snd_gf1_uart_input_open,
235 .close = snd_gf1_uart_input_close,
236 .trigger = snd_gf1_uart_input_trigger,
237};
238
239int snd_gf1_rawmidi_new(snd_gus_card_t * gus, int device, snd_rawmidi_t ** rrawmidi)
240{
241 snd_rawmidi_t *rmidi;
242 int err;
243
244 if (rrawmidi)
245 *rrawmidi = NULL;
246 if ((err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi)) < 0)
247 return err;
248 strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1");
249 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_gf1_uart_output);
250 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_gf1_uart_input);
251 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
252 rmidi->private_data = gus;
253 gus->midi_uart = rmidi;
254 if (rrawmidi)
255 *rrawmidi = rmidi;
256 return err;
257}
diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c
new file mode 100644
index 000000000000..b72bcfb28617
--- /dev/null
+++ b/sound/isa/gus/gus_volume.c
@@ -0,0 +1,210 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 *
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/time.h>
23#include <sound/core.h>
24#include <sound/gus.h>
25#define __GUS_TABLES_ALLOC__
26#include "gus_tables.h"
27
28EXPORT_SYMBOL(snd_gf1_atten_table); /* for snd-gus-synth module */
29
30unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol)
31{
32 unsigned short e, m, tmp;
33
34 if (vol > 65535)
35 vol = 65535;
36 tmp = vol;
37 e = 7;
38 if (tmp < 128) {
39 while (e > 0 && tmp < (1 << e))
40 e--;
41 } else {
42 while (tmp > 255) {
43 tmp >>= 1;
44 e++;
45 }
46 }
47 m = vol - (1 << e);
48 if (m > 0) {
49 if (e > 8)
50 m >>= e - 8;
51 else if (e < 8)
52 m <<= 8 - e;
53 m &= 255;
54 }
55 return (e << 8) | m;
56}
57
58unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol)
59{
60 unsigned int rvol;
61 unsigned short e, m;
62
63 if (!gf1_vol)
64 return 0;
65 e = gf1_vol >> 8;
66 m = (unsigned char) gf1_vol;
67 rvol = 1 << e;
68 if (e > 8)
69 return rvol | (m << (e - 8));
70 return rvol | (m >> (8 - e));
71}
72
73unsigned int snd_gf1_calc_ramp_rate(snd_gus_card_t * gus,
74 unsigned short start,
75 unsigned short end,
76 unsigned int us)
77{
78 static unsigned char vol_rates[19] =
79 {
80 23, 24, 26, 28, 29, 31, 32, 34,
81 36, 37, 39, 40, 42, 44, 45, 47,
82 49, 50, 52
83 };
84 unsigned short range, increment, value, i;
85
86 start >>= 4;
87 end >>= 4;
88 if (start < end)
89 us /= end - start;
90 else
91 us /= start - end;
92 range = 4;
93 value = gus->gf1.enh_mode ?
94 vol_rates[0] :
95 vol_rates[gus->gf1.active_voices - 14];
96 for (i = 0; i < 3; i++) {
97 if (us < value) {
98 range = i;
99 break;
100 } else
101 value <<= 3;
102 }
103 if (range == 4) {
104 range = 3;
105 increment = 1;
106 } else
107 increment = (value + (value >> 1)) / us;
108 return (range << 6) | (increment & 0x3f);
109}
110
111unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16)
112{
113 freq16 >>= 3;
114 if (freq16 < 50)
115 freq16 = 50;
116 if (freq16 & 0xf8000000) {
117 freq16 = ~0xf8000000;
118 snd_printk("snd_gf1_translate_freq: overflow - freq = 0x%x\n", freq16);
119 }
120 return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq;
121}
122
123short snd_gf1_compute_vibrato(short cents, unsigned short fc_register)
124{
125 static short vibrato_table[] =
126 {
127 0, 0, 32, 592, 61, 1175, 93, 1808,
128 124, 2433, 152, 3007, 182, 3632, 213, 4290,
129 241, 4834, 255, 5200
130 };
131
132 long depth;
133 short *vi1, *vi2, pcents, v1;
134
135 pcents = cents < 0 ? -cents : cents;
136 for (vi1 = vibrato_table, vi2 = vi1 + 2; pcents > *vi2; vi1 = vi2, vi2 += 2);
137 v1 = *(vi1 + 1);
138 /* The FC table above is a list of pairs. The first number in the pair */
139 /* is the cents index from 0-255 cents, and the second number in the */
140 /* pair is the FC adjustment needed to change the pitch by the indexed */
141 /* number of cents. The table was created for an FC of 32768. */
142 /* The following expression does a linear interpolation against the */
143 /* approximated log curve in the table above, and then scales the number */
144 /* by the FC before the LFO. This calculation also adjusts the output */
145 /* value to produce the appropriate depth for the hardware. The depth */
146 /* is 2 * desired FC + 1. */
147 depth = (((int) (*(vi2 + 1) - *vi1) * (pcents - *vi1) / (*vi2 - *vi1)) + v1) * fc_register >> 14;
148 if (depth)
149 depth++;
150 if (depth > 255)
151 depth = 255;
152 return cents < 0 ? -(short) depth : (short) depth;
153}
154
155unsigned short snd_gf1_compute_pitchbend(unsigned short pitchbend, unsigned short sens)
156{
157 static long log_table[] = {1024, 1085, 1149, 1218, 1290, 1367, 1448, 1534, 1625, 1722, 1825, 1933};
158 int wheel, sensitivity;
159 unsigned int mantissa, f1, f2;
160 unsigned short semitones, f1_index, f2_index, f1_power, f2_power;
161 char bend_down = 0;
162 int bend;
163
164 if (!sens)
165 return 1024;
166 wheel = (int) pitchbend - 8192;
167 sensitivity = ((int) sens * wheel) / 128;
168 if (sensitivity < 0) {
169 bend_down = 1;
170 sensitivity = -sensitivity;
171 }
172 semitones = (unsigned int) (sensitivity >> 13);
173 mantissa = sensitivity % 8192;
174 f1_index = semitones % 12;
175 f2_index = (semitones + 1) % 12;
176 f1_power = semitones / 12;
177 f2_power = (semitones + 1) / 12;
178 f1 = log_table[f1_index] << f1_power;
179 f2 = log_table[f2_index] << f2_power;
180 bend = (int) ((((f2 - f1) * mantissa) >> 13) + f1);
181 if (bend_down)
182 bend = 1048576L / bend;
183 return bend;
184}
185
186unsigned short snd_gf1_compute_freq(unsigned int freq,
187 unsigned int rate,
188 unsigned short mix_rate)
189{
190 unsigned int fc;
191 int scale = 0;
192
193 while (freq >= 4194304L) {
194 scale++;
195 freq >>= 1;
196 }
197 fc = (freq << 10) / rate;
198 if (fc > 97391L) {
199 fc = 97391;
200 snd_printk("patch: (1) fc frequency overflow - %u\n", fc);
201 }
202 fc = (fc * 44100UL) / mix_rate;
203 while (scale--)
204 fc <<= 1;
205 if (fc > 65535L) {
206 fc = 65535;
207 snd_printk("patch: (2) fc frequency overflow - %u\n", fc);
208 }
209 return (unsigned short) fc;
210}
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
new file mode 100644
index 000000000000..a99fa5040b46
--- /dev/null
+++ b/sound/isa/gus/gusclassic.c
@@ -0,0 +1,260 @@
1/*
2 * Driver for Gravis UltraSound Classic soundcard
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <asm/dma.h>
24#include <linux/init.h>
25#include <linux/delay.h>
26#include <linux/time.h>
27#include <linux/moduleparam.h>
28#include <sound/core.h>
29#include <sound/gus.h>
30#define SNDRV_LEGACY_AUTO_PROBE
31#define SNDRV_LEGACY_FIND_FREE_IRQ
32#define SNDRV_LEGACY_FIND_FREE_DMA
33#include <sound/initval.h>
34
35MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
36MODULE_DESCRIPTION("Gravis UltraSound Classic");
37MODULE_LICENSE("GPL");
38MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Classic}}");
39
40static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
41static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
42static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
43static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x230,0x240,0x250,0x260 */
44static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 3,5,9,11,12,15 */
45static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
46static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
47static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
48 /* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
49static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
50static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
51
52module_param_array(index, int, NULL, 0444);
53MODULE_PARM_DESC(index, "Index value for GUS Classic soundcard.");
54module_param_array(id, charp, NULL, 0444);
55MODULE_PARM_DESC(id, "ID string for GUS Classic soundcard.");
56module_param_array(enable, bool, NULL, 0444);
57MODULE_PARM_DESC(enable, "Enable GUS Classic soundcard.");
58module_param_array(port, long, NULL, 0444);
59MODULE_PARM_DESC(port, "Port # for GUS Classic driver.");
60module_param_array(irq, int, NULL, 0444);
61MODULE_PARM_DESC(irq, "IRQ # for GUS Classic driver.");
62module_param_array(dma1, int, NULL, 0444);
63MODULE_PARM_DESC(dma1, "DMA1 # for GUS Classic driver.");
64module_param_array(dma2, int, NULL, 0444);
65MODULE_PARM_DESC(dma2, "DMA2 # for GUS Classic driver.");
66module_param_array(joystick_dac, int, NULL, 0444);
67MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Classic driver.");
68module_param_array(channels, int, NULL, 0444);
69MODULE_PARM_DESC(channels, "GF1 channels for GUS Classic driver.");
70module_param_array(pcm_channels, int, NULL, 0444);
71MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Classic driver.");
72
73static snd_card_t *snd_gusclassic_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
74
75
76static int __init snd_gusclassic_detect(snd_gus_card_t * gus)
77{
78 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
79#ifdef CONFIG_SND_DEBUG_DETECT
80 {
81 unsigned char d;
82
83 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) {
84 snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
85 return -ENODEV;
86 }
87 }
88#else
89 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0)
90 return -ENODEV;
91#endif
92 udelay(160);
93 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */
94 udelay(160);
95#ifdef CONFIG_SND_DEBUG_DETECT
96 {
97 unsigned char d;
98
99 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) {
100 snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
101 return -ENODEV;
102 }
103 }
104#else
105 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1)
106 return -ENODEV;
107#endif
108
109 return 0;
110}
111
112static void __init snd_gusclassic_init(int dev, snd_gus_card_t * gus)
113{
114 gus->equal_irq = 0;
115 gus->codec_flag = 0;
116 gus->max_flag = 0;
117 gus->joystick_dac = joystick_dac[dev];
118}
119
120static int __init snd_gusclassic_probe(int dev)
121{
122 static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, 4, -1};
123 static int possible_dmas[] = {5, 6, 7, 1, 3, -1};
124 int xirq, xdma1, xdma2;
125 snd_card_t *card;
126 struct snd_gusclassic *guscard;
127 snd_gus_card_t *gus = NULL;
128 int err;
129
130 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
131 if (card == NULL)
132 return -ENOMEM;
133 guscard = (struct snd_gusclassic *)card->private_data;
134 if (pcm_channels[dev] < 2)
135 pcm_channels[dev] = 2;
136
137 xirq = irq[dev];
138 if (xirq == SNDRV_AUTO_IRQ) {
139 if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
140 snd_card_free(card);
141 snd_printk("unable to find a free IRQ\n");
142 return -EBUSY;
143 }
144 }
145 xdma1 = dma1[dev];
146 if (xdma1 == SNDRV_AUTO_DMA) {
147 if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
148 snd_card_free(card);
149 snd_printk("unable to find a free DMA1\n");
150 return -EBUSY;
151 }
152 }
153 xdma2 = dma2[dev];
154 if (xdma2 == SNDRV_AUTO_DMA) {
155 if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
156 snd_card_free(card);
157 snd_printk("unable to find a free DMA2\n");
158 return -EBUSY;
159 }
160 }
161
162
163 if ((err = snd_gus_create(card,
164 port[dev],
165 xirq, xdma1, xdma2,
166 0, channels[dev], pcm_channels[dev],
167 0, &gus)) < 0) {
168 snd_card_free(card);
169 return err;
170 }
171 if ((err = snd_gusclassic_detect(gus)) < 0) {
172 snd_card_free(card);
173 return err;
174 }
175 snd_gusclassic_init(dev, gus);
176 if ((err = snd_gus_initialize(gus)) < 0) {
177 snd_card_free(card);
178 return err;
179 }
180 if (gus->max_flag || gus->ess_flag) {
181 snd_printdd("GUS Classic or ACE soundcard was not detected at 0x%lx\n", gus->gf1.port);
182 snd_card_free(card);
183 return -ENODEV;
184 }
185 if ((err = snd_gf1_new_mixer(gus)) < 0) {
186 snd_card_free(card);
187 return err;
188 }
189 if ((err = snd_gf1_pcm_new(gus, 0, 0, NULL)) < 0) {
190 snd_card_free(card);
191 return err;
192 }
193 if (!gus->ace_flag) {
194 if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) {
195 snd_card_free(card);
196 return err;
197 }
198 }
199 sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %d, dma %d", gus->gf1.port, xirq, xdma1);
200 if (dma2 >= 0)
201 sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
202 if ((err = snd_card_register(card)) < 0) {
203 snd_card_free(card);
204 return err;
205 }
206 snd_gusclassic_cards[dev] = card;
207 return 0;
208}
209
210static int __init snd_gusclassic_legacy_auto_probe(unsigned long xport)
211{
212 static int dev;
213 int res;
214
215 for ( ; dev < SNDRV_CARDS; dev++) {
216 if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT)
217 continue;
218 port[dev] = xport;
219 res = snd_gusclassic_probe(dev);
220 if (res < 0)
221 port[dev] = SNDRV_AUTO_PORT;
222 return res;
223 }
224 return -ENODEV;
225}
226
227static int __init alsa_card_gusclassic_init(void)
228{
229 static unsigned long possible_ports[] = {0x220, 0x230, 0x240, 0x250, 0x260, -1};
230 int dev, cards, i;
231
232 for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
233 if (port[dev] == SNDRV_AUTO_PORT)
234 continue;
235 if (snd_gusclassic_probe(dev) >= 0)
236 cards++;
237 }
238 i = snd_legacy_auto_probe(possible_ports, snd_gusclassic_legacy_auto_probe);
239 if (i > 0)
240 cards += i;
241
242 if (!cards) {
243#ifdef MODULE
244 printk(KERN_ERR "GUS Classic soundcard not found or device busy\n");
245#endif
246 return -ENODEV;
247 }
248 return 0;
249}
250
251static void __exit alsa_card_gusclassic_exit(void)
252{
253 int idx;
254
255 for (idx = 0; idx < SNDRV_CARDS; idx++)
256 snd_card_free(snd_gusclassic_cards[idx]);
257}
258
259module_init(alsa_card_gusclassic_init)
260module_exit(alsa_card_gusclassic_exit)
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
new file mode 100644
index 000000000000..bc6fecb18dcf
--- /dev/null
+++ b/sound/isa/gus/gusextreme.c
@@ -0,0 +1,374 @@
1/*
2 * Driver for Gravis UltraSound Extreme soundcards
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <asm/dma.h>
24#include <linux/init.h>
25#include <linux/delay.h>
26#include <linux/time.h>
27#include <linux/moduleparam.h>
28#include <sound/core.h>
29#include <sound/gus.h>
30#include <sound/es1688.h>
31#include <sound/mpu401.h>
32#include <sound/opl3.h>
33#define SNDRV_LEGACY_AUTO_PROBE
34#define SNDRV_LEGACY_FIND_FREE_IRQ
35#define SNDRV_LEGACY_FIND_FREE_DMA
36#include <sound/initval.h>
37
38MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
39MODULE_DESCRIPTION("Gravis UltraSound Extreme");
40MODULE_LICENSE("GPL");
41MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Extreme}}");
42
43static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
44static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
45static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
46static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
47static long gf1_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x210,0x220,0x230,0x240,0x250,0x260,0x270 */
48static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x300,0x310,0x320 */
49static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
50static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
51static int gf1_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,3,5,9,11,12,15 */
52static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
53static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
54static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
55 /* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
56static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
57static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
58
59module_param_array(index, int, NULL, 0444);
60MODULE_PARM_DESC(index, "Index value for GUS Extreme soundcard.");
61module_param_array(id, charp, NULL, 0444);
62MODULE_PARM_DESC(id, "ID string for GUS Extreme soundcard.");
63module_param_array(enable, bool, NULL, 0444);
64MODULE_PARM_DESC(enable, "Enable GUS Extreme soundcard.");
65module_param_array(port, long, NULL, 0444);
66MODULE_PARM_DESC(port, "Port # for GUS Extreme driver.");
67module_param_array(gf1_port, long, NULL, 0444);
68MODULE_PARM_DESC(gf1_port, "GF1 port # for GUS Extreme driver (optional).");
69module_param_array(mpu_port, long, NULL, 0444);
70MODULE_PARM_DESC(mpu_port, "MPU-401 port # for GUS Extreme driver.");
71module_param_array(irq, int, NULL, 0444);
72MODULE_PARM_DESC(irq, "IRQ # for GUS Extreme driver.");
73module_param_array(mpu_irq, int, NULL, 0444);
74MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for GUS Extreme driver.");
75module_param_array(gf1_irq, int, NULL, 0444);
76MODULE_PARM_DESC(gf1_irq, "GF1 IRQ # for GUS Extreme driver.");
77module_param_array(dma8, int, NULL, 0444);
78MODULE_PARM_DESC(dma8, "8-bit DMA # for GUS Extreme driver.");
79module_param_array(dma1, int, NULL, 0444);
80MODULE_PARM_DESC(dma1, "GF1 DMA # for GUS Extreme driver.");
81module_param_array(joystick_dac, int, NULL, 0444);
82MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Extreme driver.");
83module_param_array(channels, int, NULL, 0444);
84MODULE_PARM_DESC(channels, "GF1 channels for GUS Extreme driver.");
85module_param_array(pcm_channels, int, NULL, 0444);
86MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Extreme driver.");
87
88static snd_card_t *snd_gusextreme_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
89
90
91static int __init snd_gusextreme_detect(int dev,
92 snd_card_t * card,
93 snd_gus_card_t * gus,
94 es1688_t *es1688)
95{
96 unsigned long flags;
97
98 /*
99 * This is main stuff - enable access to GF1 chip...
100 * I'm not sure, if this will work for card which have
101 * ES1688 chip in another place than 0x220.
102 *
103 * I used reverse-engineering in DOSEMU. [--jk]
104 *
105 * ULTRINIT.EXE:
106 * 0x230 = 0,2,3
107 * 0x240 = 2,0,1
108 * 0x250 = 2,0,3
109 * 0x260 = 2,2,1
110 */
111
112 spin_lock_irqsave(&es1688->mixer_lock, flags);
113 snd_es1688_mixer_write(es1688, 0x40, 0x0b); /* don't change!!! */
114 spin_unlock_irqrestore(&es1688->mixer_lock, flags);
115 spin_lock_irqsave(&es1688->reg_lock, flags);
116 outb(gf1_port[dev] & 0x040 ? 2 : 0, ES1688P(es1688, INIT1));
117 outb(0, 0x201);
118 outb(gf1_port[dev] & 0x020 ? 2 : 0, ES1688P(es1688, INIT1));
119 outb(0, 0x201);
120 outb(gf1_port[dev] & 0x010 ? 3 : 1, ES1688P(es1688, INIT1));
121 spin_unlock_irqrestore(&es1688->reg_lock, flags);
122
123 udelay(100);
124
125 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
126#ifdef CONFIG_SND_DEBUG_DETECT
127 {
128 unsigned char d;
129
130 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) {
131 snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
132 return -EIO;
133 }
134 }
135#else
136 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0)
137 return -EIO;
138#endif
139 udelay(160);
140 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */
141 udelay(160);
142#ifdef CONFIG_SND_DEBUG_DETECT
143 {
144 unsigned char d;
145
146 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) {
147 snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
148 return -EIO;
149 }
150 }
151#else
152 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1)
153 return -EIO;
154#endif
155
156 return 0;
157}
158
159static void __init snd_gusextreme_init(int dev, snd_gus_card_t * gus)
160{
161 gus->joystick_dac = joystick_dac[dev];
162}
163
164static int __init snd_gusextreme_mixer(es1688_t *chip)
165{
166 snd_card_t *card = chip->card;
167 snd_ctl_elem_id_t id1, id2;
168 int err;
169
170 memset(&id1, 0, sizeof(id1));
171 memset(&id2, 0, sizeof(id2));
172 id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
173 /* reassign AUX to SYNTHESIZER */
174 strcpy(id1.name, "Aux Playback Volume");
175 strcpy(id2.name, "Synth Playback Volume");
176 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
177 return err;
178 /* reassign Master Playback Switch to Synth Playback Switch */
179 strcpy(id1.name, "Master Playback Switch");
180 strcpy(id2.name, "Synth Playback Switch");
181 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
182 return err;
183 return 0;
184}
185
186static int __init snd_gusextreme_probe(int dev)
187{
188 static int possible_ess_irqs[] = {5, 9, 10, 7, -1};
189 static int possible_ess_dmas[] = {1, 3, 0, -1};
190 static int possible_gf1_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
191 static int possible_gf1_dmas[] = {5, 6, 7, 1, 3, -1};
192 int xgf1_irq, xgf1_dma, xess_irq, xmpu_irq, xess_dma;
193 snd_card_t *card;
194 struct snd_gusextreme *acard;
195 snd_gus_card_t *gus;
196 es1688_t *es1688;
197 opl3_t *opl3;
198 int err;
199
200 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
201 if (card == NULL)
202 return -ENOMEM;
203 acard = (struct snd_gusextreme *)card->private_data;
204
205 xgf1_irq = gf1_irq[dev];
206 if (xgf1_irq == SNDRV_AUTO_IRQ) {
207 if ((xgf1_irq = snd_legacy_find_free_irq(possible_gf1_irqs)) < 0) {
208 snd_printk("unable to find a free IRQ for GF1\n");
209 err = -EBUSY;
210 goto out;
211 }
212 }
213 xess_irq = irq[dev];
214 if (xess_irq == SNDRV_AUTO_IRQ) {
215 if ((xess_irq = snd_legacy_find_free_irq(possible_ess_irqs)) < 0) {
216 snd_printk("unable to find a free IRQ for ES1688\n");
217 err = -EBUSY;
218 goto out;
219 }
220 }
221 if (mpu_port[dev] == SNDRV_AUTO_PORT)
222 mpu_port[dev] = 0;
223 xmpu_irq = mpu_irq[dev];
224 if (xmpu_irq > 15)
225 xmpu_irq = -1;
226 xgf1_dma = dma1[dev];
227 if (xgf1_dma == SNDRV_AUTO_DMA) {
228 if ((xgf1_dma = snd_legacy_find_free_dma(possible_gf1_dmas)) < 0) {
229 snd_printk("unable to find a free DMA for GF1\n");
230 err = -EBUSY;
231 goto out;
232 }
233 }
234 xess_dma = dma8[dev];
235 if (xess_dma == SNDRV_AUTO_DMA) {
236 if ((xess_dma = snd_legacy_find_free_dma(possible_ess_dmas)) < 0) {
237 snd_printk("unable to find a free DMA for ES1688\n");
238 err = -EBUSY;
239 goto out;
240 }
241 }
242
243 if ((err = snd_es1688_create(card, port[dev], mpu_port[dev],
244 xess_irq, xmpu_irq, xess_dma,
245 ES1688_HW_1688, &es1688)) < 0)
246 goto out;
247 if (gf1_port[dev] < 0)
248 gf1_port[dev] = port[dev] + 0x20;
249 if ((err = snd_gus_create(card,
250 gf1_port[dev],
251 xgf1_irq,
252 xgf1_dma,
253 -1,
254 0, channels[dev],
255 pcm_channels[dev], 0,
256 &gus)) < 0)
257 goto out;
258
259 if ((err = snd_gusextreme_detect(dev, card, gus, es1688)) < 0)
260 goto out;
261
262 snd_gusextreme_init(dev, gus);
263 if ((err = snd_gus_initialize(gus)) < 0)
264 goto out;
265
266 if (!gus->ess_flag) {
267 snd_printdd("GUS Extreme soundcard was not detected at 0x%lx\n", gus->gf1.port);
268 err = -ENODEV;
269 goto out;
270 }
271 if ((err = snd_es1688_pcm(es1688, 0, NULL)) < 0)
272 goto out;
273
274 if ((err = snd_es1688_mixer(es1688)) < 0)
275 goto out;
276
277 snd_component_add(card, "ES1688");
278 if (pcm_channels[dev] > 0) {
279 if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
280 goto out;
281 }
282 if ((err = snd_gf1_new_mixer(gus)) < 0)
283 goto out;
284
285 if ((err = snd_gusextreme_mixer(es1688)) < 0)
286 goto out;
287
288 if (snd_opl3_create(card, es1688->port, es1688->port + 2,
289 OPL3_HW_OPL3, 0, &opl3) < 0) {
290 printk(KERN_ERR "gusextreme: opl3 not detected at 0x%lx\n", es1688->port);
291 } else {
292 if ((err = snd_opl3_hwdep_new(opl3, 0, 2, NULL)) < 0)
293 goto out;
294 }
295
296 if (es1688->mpu_port >= 0x300 &&
297 (err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
298 es1688->mpu_port, 0,
299 xmpu_irq,
300 SA_INTERRUPT,
301 NULL)) < 0)
302 goto out;
303
304 sprintf(card->longname, "Gravis UltraSound Extreme at 0x%lx, irq %i&%i, dma %i&%i",
305 es1688->port, xgf1_irq, xess_irq, xgf1_dma, xess_dma);
306 if ((err = snd_card_register(card)) < 0)
307 goto out;
308
309 snd_gusextreme_cards[dev] = card;
310 return 0;
311
312 out:
313 snd_card_free(card);
314 return err;
315}
316
317static int __init snd_gusextreme_legacy_auto_probe(unsigned long xport)
318{
319 static int dev;
320 int res;
321
322 for ( ; dev < SNDRV_CARDS; dev++) {
323 if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT)
324 continue;
325 port[dev] = xport;
326 res = snd_gusextreme_probe(dev);
327 if (res < 0)
328 port[dev] = SNDRV_AUTO_PORT;
329 return res;
330 }
331 return -ENODEV;
332}
333
334static int __init alsa_card_gusextreme_init(void)
335{
336 static unsigned long possible_ports[] = {0x220, 0x240, 0x260, -1};
337 int dev, cards, i;
338
339 for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev] > 0; dev++) {
340 if (port[dev] == SNDRV_AUTO_PORT)
341 continue;
342 if (snd_gusextreme_probe(dev) >= 0)
343 cards++;
344 }
345 i = snd_legacy_auto_probe(possible_ports, snd_gusextreme_legacy_auto_probe);
346 if (i > 0)
347 cards += i;
348
349 if (!cards) {
350#ifdef MODULE
351 printk(KERN_ERR "GUS Extreme soundcard not found or device busy\n");
352#endif
353 return -ENODEV;
354 }
355 return 0;
356}
357
358static void __exit alsa_card_gusextreme_exit(void)
359{
360 int idx;
361 snd_card_t *card;
362 struct snd_gusextreme *acard;
363
364 for (idx = 0; idx < SNDRV_CARDS; idx++) {
365 card = snd_gusextreme_cards[idx];
366 if (card == NULL)
367 continue;
368 acard = (struct snd_gusextreme *)card->private_data;
369 snd_card_free(snd_gusextreme_cards[idx]);
370 }
371}
372
373module_init(alsa_card_gusextreme_init)
374module_exit(alsa_card_gusextreme_exit)
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
new file mode 100644
index 000000000000..400ff34710fb
--- /dev/null
+++ b/sound/isa/gus/gusmax.c
@@ -0,0 +1,400 @@
1/*
2 * Driver for Gravis UltraSound MAX soundcard
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <asm/dma.h>
24#include <linux/init.h>
25#include <linux/delay.h>
26#include <linux/time.h>
27#include <linux/moduleparam.h>
28#include <sound/core.h>
29#include <sound/gus.h>
30#include <sound/cs4231.h>
31#define SNDRV_LEGACY_AUTO_PROBE
32#define SNDRV_LEGACY_FIND_FREE_IRQ
33#define SNDRV_LEGACY_FIND_FREE_DMA
34#include <sound/initval.h>
35
36MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
37MODULE_DESCRIPTION("Gravis UltraSound MAX");
38MODULE_LICENSE("GPL");
39MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound MAX}}");
40
41static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
42static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
43static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
44static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x230,0x240,0x250,0x260 */
45static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,3,5,9,11,12,15 */
46static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
47static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
48static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
49 /* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
50static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
51static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
52
53module_param_array(index, int, NULL, 0444);
54MODULE_PARM_DESC(index, "Index value for GUS MAX soundcard.");
55module_param_array(id, charp, NULL, 0444);
56MODULE_PARM_DESC(id, "ID string for GUS MAX soundcard.");
57module_param_array(enable, bool, NULL, 0444);
58MODULE_PARM_DESC(enable, "Enable GUS MAX soundcard.");
59module_param_array(port, long, NULL, 0444);
60MODULE_PARM_DESC(port, "Port # for GUS MAX driver.");
61module_param_array(irq, int, NULL, 0444);
62MODULE_PARM_DESC(irq, "IRQ # for GUS MAX driver.");
63module_param_array(dma1, int, NULL, 0444);
64MODULE_PARM_DESC(dma1, "DMA1 # for GUS MAX driver.");
65module_param_array(dma2, int, NULL, 0444);
66MODULE_PARM_DESC(dma2, "DMA2 # for GUS MAX driver.");
67module_param_array(joystick_dac, int, NULL, 0444);
68MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS MAX driver.");
69module_param_array(channels, int, NULL, 0444);
70MODULE_PARM_DESC(channels, "Used GF1 channels for GUS MAX driver.");
71module_param_array(pcm_channels, int, NULL, 0444);
72MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS MAX driver.");
73
74struct snd_gusmax {
75 int irq;
76 snd_card_t *card;
77 snd_gus_card_t *gus;
78 cs4231_t *cs4231;
79 unsigned short gus_status_reg;
80 unsigned short pcm_status_reg;
81};
82
83static snd_card_t *snd_gusmax_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
84
85
86static int __init snd_gusmax_detect(snd_gus_card_t * gus)
87{
88 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
89#ifdef CONFIG_SND_DEBUG_DETECT
90 {
91 unsigned char d;
92
93 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) {
94 snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
95 return -ENODEV;
96 }
97 }
98#else
99 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0)
100 return -ENODEV;
101#endif
102 udelay(160);
103 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */
104 udelay(160);
105#ifdef CONFIG_SND_DEBUG_DETECT
106 {
107 unsigned char d;
108
109 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) {
110 snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
111 return -ENODEV;
112 }
113 }
114#else
115 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1)
116 return -ENODEV;
117#endif
118 return 0;
119}
120
121static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
122{
123 struct snd_gusmax *maxcard = (struct snd_gusmax *) dev_id;
124 int loop, max = 5;
125 int handled = 0;
126
127 do {
128 loop = 0;
129 if (inb(maxcard->gus_status_reg)) {
130 handled = 1;
131 snd_gus_interrupt(irq, maxcard->gus, regs);
132 loop++;
133 }
134 if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
135 handled = 1;
136 snd_cs4231_interrupt(irq, maxcard->cs4231, regs);
137 loop++;
138 }
139 } while (loop && --max > 0);
140 return IRQ_RETVAL(handled);
141}
142
143static void __init snd_gusmax_init(int dev, snd_card_t * card, snd_gus_card_t * gus)
144{
145 gus->equal_irq = 1;
146 gus->codec_flag = 1;
147 gus->joystick_dac = joystick_dac[dev];
148 /* init control register */
149 gus->max_cntrl_val = (gus->gf1.port >> 4) & 0x0f;
150 if (gus->gf1.dma1 > 3)
151 gus->max_cntrl_val |= 0x10;
152 if (gus->gf1.dma2 > 3)
153 gus->max_cntrl_val |= 0x20;
154 gus->max_cntrl_val |= 0x40;
155 outb(gus->max_cntrl_val, GUSP(gus, MAXCNTRLPORT));
156}
157
158#define CS4231_PRIVATE( left, right, shift, mute ) \
159 ((left << 24)|(right << 16)|(shift<<8)|mute)
160
161static int __init snd_gusmax_mixer(cs4231_t *chip)
162{
163 snd_card_t *card = chip->card;
164 snd_ctl_elem_id_t id1, id2;
165 int err;
166
167 memset(&id1, 0, sizeof(id1));
168 memset(&id2, 0, sizeof(id2));
169 id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
170 /* reassign AUXA to SYNTHESIZER */
171 strcpy(id1.name, "Aux Playback Switch");
172 strcpy(id2.name, "Synth Playback Switch");
173 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
174 return err;
175 strcpy(id1.name, "Aux Playback Volume");
176 strcpy(id2.name, "Synth Playback Volume");
177 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
178 return err;
179 /* reassign AUXB to CD */
180 strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
181 strcpy(id2.name, "CD Playback Switch");
182 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
183 return err;
184 strcpy(id1.name, "Aux Playback Volume");
185 strcpy(id2.name, "CD Playback Volume");
186 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
187 return err;
188#if 0
189 /* reassign Mono Input to MIC */
190 if (snd_mixer_group_rename(mixer,
191 SNDRV_MIXER_IN_MONO, 0,
192 SNDRV_MIXER_IN_MIC, 0) < 0)
193 goto __error;
194 if (snd_mixer_elem_rename(mixer,
195 SNDRV_MIXER_IN_MONO, 0, SNDRV_MIXER_ETYPE_INPUT,
196 SNDRV_MIXER_IN_MIC, 0) < 0)
197 goto __error;
198 if (snd_mixer_elem_rename(mixer,
199 "Mono Capture Volume", 0, SNDRV_MIXER_ETYPE_VOLUME1,
200 "Mic Capture Volume", 0) < 0)
201 goto __error;
202 if (snd_mixer_elem_rename(mixer,
203 "Mono Capture Switch", 0, SNDRV_MIXER_ETYPE_SWITCH1,
204 "Mic Capture Switch", 0) < 0)
205 goto __error;
206#endif
207 return 0;
208}
209
210static void snd_gusmax_free(snd_card_t *card)
211{
212 struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
213
214 if (maxcard == NULL)
215 return;
216 if (maxcard->irq >= 0)
217 free_irq(maxcard->irq, (void *)maxcard);
218}
219
220static int __init snd_gusmax_probe(int dev)
221{
222 static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
223 static int possible_dmas[] = {5, 6, 7, 1, 3, -1};
224 int xirq, xdma1, xdma2, err;
225 snd_card_t *card;
226 snd_gus_card_t *gus = NULL;
227 cs4231_t *cs4231;
228 struct snd_gusmax *maxcard;
229
230 card = snd_card_new(index[dev], id[dev], THIS_MODULE,
231 sizeof(struct snd_gusmax));
232 if (card == NULL)
233 return -ENOMEM;
234 card->private_free = snd_gusmax_free;
235 maxcard = (struct snd_gusmax *)card->private_data;
236 maxcard->card = card;
237 maxcard->irq = -1;
238
239 xirq = irq[dev];
240 if (xirq == SNDRV_AUTO_IRQ) {
241 if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
242 snd_card_free(card);
243 snd_printk("unable to find a free IRQ\n");
244 return -EBUSY;
245 }
246 }
247 xdma1 = dma1[dev];
248 if (xdma1 == SNDRV_AUTO_DMA) {
249 if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
250 snd_card_free(card);
251 snd_printk("unable to find a free DMA1\n");
252 return -EBUSY;
253 }
254 }
255 xdma2 = dma2[dev];
256 if (xdma2 == SNDRV_AUTO_DMA) {
257 if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
258 snd_card_free(card);
259 snd_printk("unable to find a free DMA2\n");
260 return -EBUSY;
261 }
262 }
263
264 if ((err = snd_gus_create(card,
265 port[dev],
266 -xirq, xdma1, xdma2,
267 0, channels[dev],
268 pcm_channels[dev],
269 0, &gus)) < 0) {
270 snd_card_free(card);
271 return err;
272 }
273 if ((err = snd_gusmax_detect(gus)) < 0) {
274 snd_card_free(card);
275 return err;
276 }
277 maxcard->gus_status_reg = gus->gf1.reg_irqstat;
278 maxcard->pcm_status_reg = gus->gf1.port + 0x10c + 2;
279 snd_gusmax_init(dev, card, gus);
280 if ((err = snd_gus_initialize(gus)) < 0) {
281 snd_card_free(card);
282 return err;
283 }
284 if (!gus->max_flag) {
285 printk(KERN_ERR "GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port);
286 snd_card_free(card);
287 return -ENODEV;
288 }
289
290 if (request_irq(xirq, snd_gusmax_interrupt, SA_INTERRUPT, "GUS MAX", (void *)maxcard)) {
291 snd_card_free(card);
292 printk(KERN_ERR "gusmax: unable to grab IRQ %d\n", xirq);
293 return -EBUSY;
294 }
295 maxcard->irq = xirq;
296
297 if ((err = snd_cs4231_create(card,
298 gus->gf1.port + 0x10c, -1, xirq,
299 xdma2 < 0 ? xdma1 : xdma2, xdma1,
300 CS4231_HW_DETECT,
301 CS4231_HWSHARE_IRQ |
302 CS4231_HWSHARE_DMA1 |
303 CS4231_HWSHARE_DMA2,
304 &cs4231)) < 0) {
305 snd_card_free(card);
306 return err;
307 }
308 if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) {
309 snd_card_free(card);
310 return err;
311 }
312 if ((err = snd_cs4231_mixer(cs4231)) < 0) {
313 snd_card_free(card);
314 return err;
315 }
316 if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) {
317 snd_card_free(card);
318 return err;
319 }
320 if (pcm_channels[dev] > 0) {
321 if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) {
322 snd_card_free(card);
323 return err;
324 }
325 }
326 if ((err = snd_gusmax_mixer(cs4231)) < 0) {
327 snd_card_free(card);
328 return err;
329 }
330
331 if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) {
332 snd_card_free(card);
333 return err;
334 }
335
336 sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %i, dma %i", gus->gf1.port, xirq, xdma1);
337 if (xdma2 >= 0)
338 sprintf(card->longname + strlen(card->longname), "&%i", xdma2);
339 if ((err = snd_card_register(card)) < 0) {
340 snd_card_free(card);
341 return err;
342 }
343
344 maxcard->gus = gus;
345 maxcard->cs4231 = cs4231;
346 snd_gusmax_cards[dev] = card;
347 return 0;
348}
349
350static int __init snd_gusmax_legacy_auto_probe(unsigned long xport)
351{
352 static int dev;
353 int res;
354
355 for ( ; dev < SNDRV_CARDS; dev++) {
356 if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT)
357 continue;
358 port[dev] = xport;
359 res = snd_gusmax_probe(dev);
360 if (res < 0)
361 port[dev] = SNDRV_AUTO_PORT;
362 return res;
363 }
364 return -ENODEV;
365}
366
367static int __init alsa_card_gusmax_init(void)
368{
369 static unsigned long possible_ports[] = {0x220, 0x230, 0x240, 0x250, 0x260, -1};
370 int dev, cards, i;
371
372 for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev] > 0; dev++) {
373 if (port[dev] == SNDRV_AUTO_PORT)
374 continue;
375 if (snd_gusmax_probe(dev) >= 0)
376 cards++;
377 }
378 i = snd_legacy_auto_probe(possible_ports, snd_gusmax_legacy_auto_probe);
379 if (i > 0)
380 cards += i;
381
382 if (!cards) {
383#ifdef MODULE
384 printk(KERN_ERR "GUS MAX soundcard not found or device busy\n");
385#endif
386 return -ENODEV;
387 }
388 return 0;
389}
390
391static void __exit alsa_card_gusmax_exit(void)
392{
393 int idx;
394
395 for (idx = 0; idx < SNDRV_CARDS; idx++)
396 snd_card_free(snd_gusmax_cards[idx]);
397}
398
399module_init(alsa_card_gusmax_init)
400module_exit(alsa_card_gusmax_exit)
diff --git a/sound/isa/gus/interwave-stb.c b/sound/isa/gus/interwave-stb.c
new file mode 100644
index 000000000000..dbe4f48a9846
--- /dev/null
+++ b/sound/isa/gus/interwave-stb.c
@@ -0,0 +1,2 @@
1#define SNDRV_STB
2#include "interwave.c"
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
new file mode 100644
index 000000000000..46e867daba6a
--- /dev/null
+++ b/sound/isa/gus/interwave.c
@@ -0,0 +1,969 @@
1/*
2 * Driver for AMD InterWave soundcard
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * 1999/07/22 Erik Inge Bolso <knan@mo.himolde.no>
21 * * mixer group handlers
22 *
23 */
24
25#include <sound/driver.h>
26#include <asm/dma.h>
27#include <linux/delay.h>
28#include <linux/init.h>
29#include <linux/slab.h>
30#include <linux/pnp.h>
31#include <linux/moduleparam.h>
32#include <sound/core.h>
33#include <sound/gus.h>
34#include <sound/cs4231.h>
35#ifdef SNDRV_STB
36#include <sound/tea6330t.h>
37#endif
38#define SNDRV_LEGACY_AUTO_PROBE
39#define SNDRV_LEGACY_FIND_FREE_IRQ
40#define SNDRV_LEGACY_FIND_FREE_DMA
41#include <sound/initval.h>
42
43MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
44MODULE_LICENSE("GPL");
45#ifndef SNDRV_STB
46MODULE_DESCRIPTION("AMD InterWave");
47MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Plug & Play},"
48 "{STB,SoundRage32},"
49 "{MED,MED3210},"
50 "{Dynasonix,Dynasonix Pro},"
51 "{Panasonic,PCA761AW}}");
52#else
53MODULE_DESCRIPTION("AMD InterWave STB with TEA6330T");
54MODULE_SUPPORTED_DEVICE("{{AMD,InterWave STB with TEA6330T}}");
55#endif
56
57static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
58static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
59static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
60#ifdef CONFIG_PNP
61static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
62#endif
63static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x210,0x220,0x230,0x240,0x250,0x260 */
64#ifdef SNDRV_STB
65static long port_tc[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x350,0x360,0x370,0x380 */
66#endif
67static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,3,5,9,11,12,15 */
68static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
69static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
70static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
71 /* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
72static int midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
73static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
74static int effect[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
75
76module_param_array(index, int, NULL, 0444);
77MODULE_PARM_DESC(index, "Index value for InterWave soundcard.");
78module_param_array(id, charp, NULL, 0444);
79MODULE_PARM_DESC(id, "ID string for InterWave soundcard.");
80module_param_array(enable, bool, NULL, 0444);
81MODULE_PARM_DESC(enable, "Enable InterWave soundcard.");
82#ifdef CONFIG_PNP
83module_param_array(isapnp, bool, NULL, 0444);
84MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
85#endif
86module_param_array(port, long, NULL, 0444);
87MODULE_PARM_DESC(port, "Port # for InterWave driver.");
88#ifdef SNDRV_STB
89module_param_array(port_tc, long, NULL, 0444);
90MODULE_PARM_DESC(port_tc, "Tone control (TEA6330T - i2c bus) port # for InterWave driver.");
91#endif
92module_param_array(irq, int, NULL, 0444);
93MODULE_PARM_DESC(irq, "IRQ # for InterWave driver.");
94module_param_array(dma1, int, NULL, 0444);
95MODULE_PARM_DESC(dma1, "DMA1 # for InterWave driver.");
96module_param_array(dma2, int, NULL, 0444);
97MODULE_PARM_DESC(dma2, "DMA2 # for InterWave driver.");
98module_param_array(joystick_dac, int, NULL, 0444);
99MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for InterWave driver.");
100module_param_array(midi, int, NULL, 0444);
101MODULE_PARM_DESC(midi, "MIDI UART enable for InterWave driver.");
102module_param_array(pcm_channels, int, NULL, 0444);
103MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for InterWave driver.");
104module_param_array(effect, int, NULL, 0444);
105MODULE_PARM_DESC(effect, "Effects enable for InterWave driver.");
106
107struct snd_interwave {
108 int irq;
109 snd_card_t *card;
110 snd_gus_card_t *gus;
111 cs4231_t *cs4231;
112#ifdef SNDRV_STB
113 struct resource *i2c_res;
114#endif
115 unsigned short gus_status_reg;
116 unsigned short pcm_status_reg;
117#ifdef CONFIG_PNP
118 struct pnp_dev *dev;
119#ifdef SNDRV_STB
120 struct pnp_dev *devtc;
121#endif
122#endif
123};
124
125static snd_card_t *snd_interwave_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
126
127#ifdef CONFIG_PNP
128
129static struct pnp_card_device_id snd_interwave_pnpids[] = {
130#ifndef SNDRV_STB
131 /* Gravis UltraSound Plug & Play */
132 { .id = "GRV0001", .devs = { { .id = "GRV0000" } } },
133 /* STB SoundRage32 */
134 { .id = "STB011a", .devs = { { .id = "STB0010" } } },
135 /* MED3210 */
136 { .id = "DXP3201", .devs = { { .id = "DXP0010" } } },
137 /* Dynasonic Pro */
138 /* This device also have CDC1117:DynaSonix Pro Audio Effects Processor */
139 { .id = "CDC1111", .devs = { { .id = "CDC1112" } } },
140 /* Panasonic PCA761AW Audio Card */
141 { .id = "ADV55ff", .devs = { { .id = "ADV0010" } } },
142 /* InterWave STB without TEA6330T */
143 { .id = "ADV550a", .devs = { { .id = "ADV0010" } } },
144#else
145 /* InterWave STB with TEA6330T */
146 { .id = "ADV550a", .devs = { { .id = "ADV0010" }, { .id = "ADV0015" } } },
147#endif
148 { .id = "" }
149};
150
151MODULE_DEVICE_TABLE(pnp_card, snd_interwave_pnpids);
152
153#endif /* CONFIG_PNP */
154
155
156#ifdef SNDRV_STB
157static void snd_interwave_i2c_setlines(snd_i2c_bus_t *bus, int ctrl, int data)
158{
159 unsigned long port = bus->private_value;
160
161#if 0
162 printk("i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
163#endif
164 outb((data << 1) | ctrl, port);
165 udelay(10);
166}
167
168static int snd_interwave_i2c_getclockline(snd_i2c_bus_t *bus)
169{
170 unsigned long port = bus->private_value;
171 unsigned char res;
172
173 res = inb(port) & 1;
174#if 0
175 printk("i2c_getclockline - 0x%lx -> %i\n", port, res);
176#endif
177 return res;
178}
179
180static int snd_interwave_i2c_getdataline(snd_i2c_bus_t *bus, int ack)
181{
182 unsigned long port = bus->private_value;
183 unsigned char res;
184
185 if (ack)
186 udelay(10);
187 res = (inb(port) & 2) >> 1;
188#if 0
189 printk("i2c_getdataline - 0x%lx -> %i\n", port, res);
190#endif
191 return res;
192}
193
194static snd_i2c_bit_ops_t snd_interwave_i2c_bit_ops = {
195 .setlines = snd_interwave_i2c_setlines,
196 .getclock = snd_interwave_i2c_getclockline,
197 .getdata = snd_interwave_i2c_getdataline,
198};
199
200static int __devinit snd_interwave_detect_stb(struct snd_interwave *iwcard,
201 snd_gus_card_t * gus, int dev,
202 snd_i2c_bus_t **rbus)
203{
204 unsigned long port;
205 snd_i2c_bus_t *bus;
206 snd_card_t *card = iwcard->card;
207 char name[32];
208 int err;
209
210 *rbus = NULL;
211 port = port_tc[dev];
212 if (port == SNDRV_AUTO_PORT) {
213 port = 0x350;
214 if (gus->gf1.port == 0x250) {
215 port = 0x360;
216 }
217 while (port <= 0x380) {
218 if ((iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)")) != NULL)
219 break;
220 port += 0x10;
221 }
222 } else {
223 iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)");
224 }
225 if (iwcard->i2c_res == NULL) {
226 snd_printk(KERN_ERR "interwave: can't grab i2c bus port\n");
227 return -ENODEV;
228 }
229
230 sprintf(name, "InterWave-%i", card->number);
231 if ((err = snd_i2c_bus_create(card, name, NULL, &bus)) < 0)
232 return err;
233 bus->private_value = port;
234 bus->hw_ops.bit = &snd_interwave_i2c_bit_ops;
235 if ((err = snd_tea6330t_detect(bus, 0)) < 0)
236 return err;
237 *rbus = bus;
238 return 0;
239}
240#endif
241
242static int __devinit snd_interwave_detect(struct snd_interwave *iwcard,
243 snd_gus_card_t * gus,
244 int dev
245#ifdef SNDRV_STB
246 , snd_i2c_bus_t **rbus
247#endif
248 )
249{
250 unsigned long flags;
251 unsigned char rev1, rev2;
252
253 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
254#ifdef CONFIG_SND_DEBUG_DETECT
255 {
256 int d;
257
258 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) {
259 snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
260 return -ENODEV;
261 }
262 }
263#else
264 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0)
265 return -ENODEV;
266#endif
267 udelay(160);
268 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */
269 udelay(160);
270#ifdef CONFIG_SND_DEBUG_DETECT
271 {
272 int d;
273
274 if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) {
275 snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
276 return -ENODEV;
277 }
278 }
279#else
280 if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1)
281 return -ENODEV;
282#endif
283
284 spin_lock_irqsave(&gus->reg_lock, flags);
285 rev1 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
286 snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, ~rev1);
287 rev2 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
288 snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, rev1);
289 spin_unlock_irqrestore(&gus->reg_lock, flags);
290 snd_printdd("[0x%lx] InterWave check - rev1=0x%x, rev2=0x%x\n", gus->gf1.port, rev1, rev2);
291 if ((rev1 & 0xf0) == (rev2 & 0xf0) &&
292 (rev1 & 0x0f) != (rev2 & 0x0f)) {
293 snd_printdd("[0x%lx] InterWave check - passed\n", gus->gf1.port);
294 gus->interwave = 1;
295 strcpy(gus->card->shortname, "AMD InterWave");
296 gus->revision = rev1 >> 4;
297#ifndef SNDRV_STB
298 return 0; /* ok.. We have an InterWave board */
299#else
300 return snd_interwave_detect_stb(iwcard, gus, dev, rbus);
301#endif
302 }
303 snd_printdd("[0x%lx] InterWave check - failed\n", gus->gf1.port);
304 return -ENODEV;
305}
306
307static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs *regs)
308{
309 struct snd_interwave *iwcard = (struct snd_interwave *) dev_id;
310 int loop, max = 5;
311 int handled = 0;
312
313 do {
314 loop = 0;
315 if (inb(iwcard->gus_status_reg)) {
316 handled = 1;
317 snd_gus_interrupt(irq, iwcard->gus, regs);
318 loop++;
319 }
320 if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
321 handled = 1;
322 snd_cs4231_interrupt(irq, iwcard->cs4231, regs);
323 loop++;
324 }
325 } while (loop && --max > 0);
326 return IRQ_RETVAL(handled);
327}
328
329static void __devinit snd_interwave_reset(snd_gus_card_t * gus)
330{
331 snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x00);
332 udelay(160);
333 snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x01);
334 udelay(160);
335}
336
337static void __devinit snd_interwave_bank_sizes(snd_gus_card_t * gus, int *sizes)
338{
339 unsigned int idx;
340 unsigned int local;
341 unsigned char d;
342
343 for (idx = 0; idx < 4; idx++) {
344 sizes[idx] = 0;
345 d = 0x55;
346 for (local = idx << 22;
347 local < (idx << 22) + 0x400000;
348 local += 0x40000, d++) {
349 snd_gf1_poke(gus, local, d);
350 snd_gf1_poke(gus, local + 1, d + 1);
351#if 0
352 printk("d = 0x%x, local = 0x%x, local + 1 = 0x%x, idx << 22 = 0x%x\n",
353 d,
354 snd_gf1_peek(gus, local),
355 snd_gf1_peek(gus, local + 1),
356 snd_gf1_peek(gus, idx << 22));
357#endif
358 if (snd_gf1_peek(gus, local) != d ||
359 snd_gf1_peek(gus, local + 1) != d + 1 ||
360 snd_gf1_peek(gus, idx << 22) != 0x55)
361 break;
362 sizes[idx]++;
363 }
364 }
365#if 0
366 printk("sizes: %i %i %i %i\n", sizes[0], sizes[1], sizes[2], sizes[3]);
367#endif
368}
369
370struct rom_hdr {
371 /* 000 */ unsigned char iwave[8];
372 /* 008 */ unsigned char rom_hdr_revision;
373 /* 009 */ unsigned char series_number;
374 /* 010 */ unsigned char series_name[16];
375 /* 026 */ unsigned char date[10];
376 /* 036 */ unsigned short vendor_revision_major;
377 /* 038 */ unsigned short vendor_revision_minor;
378 /* 040 */ unsigned int rom_size;
379 /* 044 */ unsigned char copyright[128];
380 /* 172 */ unsigned char vendor_name[64];
381 /* 236 */ unsigned char rom_description[128];
382 /* 364 */ unsigned char pad[147];
383 /* 511 */ unsigned char csum;
384};
385
386static void __devinit snd_interwave_detect_memory(snd_gus_card_t * gus)
387{
388 static unsigned int lmc[13] =
389 {
390 0x00000001, 0x00000101, 0x01010101, 0x00000401,
391 0x04040401, 0x00040101, 0x04040101, 0x00000004,
392 0x00000404, 0x04040404, 0x00000010, 0x00001010,
393 0x10101010
394 };
395
396 int bank_pos, pages;
397 unsigned int i, lmct;
398 int psizes[4];
399 unsigned char iwave[8];
400 unsigned char csum;
401
402 snd_interwave_reset(gus);
403 snd_gf1_write8(gus, SNDRV_GF1_GB_GLOBAL_MODE, snd_gf1_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE) | 0x01); /* enhanced mode */
404 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01); /* DRAM I/O cycles selected */
405 snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xff10) | 0x004c);
406 /* ok.. simple test of memory size */
407 pages = 0;
408 snd_gf1_poke(gus, 0, 0x55);
409 snd_gf1_poke(gus, 1, 0xaa);
410#if 1
411 if (snd_gf1_peek(gus, 0) == 0x55 && snd_gf1_peek(gus, 1) == 0xaa)
412#else
413 if (0) /* ok.. for testing of 0k RAM */
414#endif
415 {
416 snd_interwave_bank_sizes(gus, psizes);
417 lmct = (psizes[3] << 24) | (psizes[2] << 16) |
418 (psizes[1] << 8) | psizes[0];
419#if 0
420 printk("lmct = 0x%08x\n", lmct);
421#endif
422 for (i = 0; i < ARRAY_SIZE(lmc); i++)
423 if (lmct == lmc[i]) {
424#if 0
425 printk("found !!! %i\n", i);
426#endif
427 snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i);
428 snd_interwave_bank_sizes(gus, psizes);
429 break;
430 }
431 if (i >= ARRAY_SIZE(lmc) && !gus->gf1.enh_mode)
432 snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | 2);
433 for (i = 0; i < 4; i++) {
434 gus->gf1.mem_alloc.banks_8[i].address =
435 gus->gf1.mem_alloc.banks_16[i].address = i << 22;
436 gus->gf1.mem_alloc.banks_8[i].size =
437 gus->gf1.mem_alloc.banks_16[i].size = psizes[i] << 18;
438 pages += psizes[i];
439 }
440 }
441 pages <<= 18;
442 gus->gf1.memory = pages;
443
444 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x03); /* select ROM */
445 snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xff1f) | (4 << 5));
446 gus->gf1.rom_banks = 0;
447 gus->gf1.rom_memory = 0;
448 for (bank_pos = 0; bank_pos < 16L * 1024L * 1024L; bank_pos += 4L * 1024L * 1024L) {
449 for (i = 0; i < 8; ++i)
450 iwave[i] = snd_gf1_peek(gus, bank_pos + i);
451#ifdef CONFIG_SND_DEBUG_ROM
452 printk("ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos,
453 iwave[0], iwave[1], iwave[2], iwave[3],
454 iwave[4], iwave[5], iwave[6], iwave[7]);
455#endif
456 if (strncmp(iwave, "INTRWAVE", 8))
457 continue; /* first check */
458 csum = 0;
459 for (i = 0; i < sizeof(struct rom_hdr); i++)
460 csum += snd_gf1_peek(gus, bank_pos + i);
461#ifdef CONFIG_SND_DEBUG_ROM
462 printk("ROM checksum = 0x%x (computed)\n", csum);
463#endif
464 if (csum != 0)
465 continue; /* not valid rom */
466 gus->gf1.rom_banks++;
467 gus->gf1.rom_present |= 1 << (bank_pos >> 22);
468 gus->gf1.rom_memory = snd_gf1_peek(gus, bank_pos + 40) |
469 (snd_gf1_peek(gus, bank_pos + 41) << 8) |
470 (snd_gf1_peek(gus, bank_pos + 42) << 16) |
471 (snd_gf1_peek(gus, bank_pos + 43) << 24);
472 }
473#if 0
474 if (gus->gf1.rom_memory > 0) {
475 if (gus->gf1.rom_banks == 1 && gus->gf1.rom_present == 8)
476 gus->card->type = SNDRV_CARD_TYPE_IW_DYNASONIC;
477 }
478#endif
479 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x00); /* select RAM */
480
481 if (!gus->gf1.enh_mode)
482 snd_interwave_reset(gus);
483}
484
485static void __devinit snd_interwave_init(int dev, snd_gus_card_t * gus)
486{
487 unsigned long flags;
488
489 /* ok.. some InterWave specific initialization */
490 spin_lock_irqsave(&gus->reg_lock, flags);
491 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00);
492 snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f);
493 snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49);
494 snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11);
495 snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00);
496 snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30);
497 snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00);
498 spin_unlock_irqrestore(&gus->reg_lock, flags);
499 gus->equal_irq = 1;
500 gus->codec_flag = 1;
501 gus->interwave = 1;
502 gus->max_flag = 1;
503 gus->joystick_dac = joystick_dac[dev];
504
505}
506
507static snd_kcontrol_new_t snd_interwave_controls[] = {
508CS4231_DOUBLE("Master Playback Switch", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
509CS4231_DOUBLE("Master Playback Volume", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
510CS4231_DOUBLE("Mic Playback Switch", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
511CS4231_DOUBLE("Mic Playback Volume", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
512};
513
514static int __devinit snd_interwave_mixer(cs4231_t *chip)
515{
516 snd_card_t *card = chip->card;
517 snd_ctl_elem_id_t id1, id2;
518 unsigned int idx;
519 int err;
520
521 memset(&id1, 0, sizeof(id1));
522 memset(&id2, 0, sizeof(id2));
523 id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
524#if 0
525 /* remove mono microphone controls */
526 strcpy(id1.name, "Mic Playback Switch");
527 if ((err = snd_ctl_remove_id(card, &id1)) < 0)
528 return err;
529 strcpy(id1.name, "Mic Playback Volume");
530 if ((err = snd_ctl_remove_id(card, &id1)) < 0)
531 return err;
532#endif
533 /* add new master and mic controls */
534 for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++)
535 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0)
536 return err;
537 snd_cs4231_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
538 snd_cs4231_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
539 snd_cs4231_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
540 snd_cs4231_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
541 /* reassign AUXA to SYNTHESIZER */
542 strcpy(id1.name, "Aux Playback Switch");
543 strcpy(id2.name, "Synth Playback Switch");
544 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
545 return err;
546 strcpy(id1.name, "Aux Playback Volume");
547 strcpy(id2.name, "Synth Playback Volume");
548 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
549 return err;
550 /* reassign AUXB to CD */
551 strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
552 strcpy(id2.name, "CD Playback Switch");
553 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
554 return err;
555 strcpy(id1.name, "Aux Playback Volume");
556 strcpy(id2.name, "CD Playback Volume");
557 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
558 return err;
559 return 0;
560}
561
562#ifdef CONFIG_PNP
563
564static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
565 struct pnp_card_link *card,
566 const struct pnp_card_device_id *id)
567{
568 struct pnp_dev *pdev;
569 struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
570 int err;
571
572 iwcard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
573 if (iwcard->dev == NULL) {
574 kfree(cfg);
575 return -EBUSY;
576 }
577#ifdef SNDRV_STB
578 iwcard->devtc = pnp_request_card_device(card, id->devs[1].id, NULL);
579 if (iwcard->devtc == NULL) {
580 kfree(cfg);
581 return -EBUSY;
582 }
583#endif
584 /* Synth & Codec initialization */
585 pdev = iwcard->dev;
586 pnp_init_resource_table(cfg);
587 if (port[dev] != SNDRV_AUTO_PORT) {
588 pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
589 pnp_resource_change(&cfg->port_resource[1], port[dev] + 0x100, 12);
590 pnp_resource_change(&cfg->port_resource[2], port[dev] + 0x10c, 4);
591 }
592 if (dma1[dev] != SNDRV_AUTO_DMA)
593 pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
594 if (dma2[dev] != SNDRV_AUTO_DMA)
595 pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
596 if (dma2[dev] < 0)
597 pnp_resource_change(&cfg->dma_resource[1], 4, 1);
598 if (irq[dev] != SNDRV_AUTO_IRQ)
599 pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
600 if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
601 snd_printk(KERN_ERR "InterWave - Synth - the requested resources are invalid, using auto config\n");
602 err = pnp_activate_dev(pdev);
603 if (err < 0) {
604 kfree(cfg);
605 snd_printk(KERN_ERR "InterWave PnP configure failure (out of resources?)\n");
606 return err;
607 }
608 if (pnp_port_start(pdev, 0) + 0x100 != pnp_port_start(pdev, 1) ||
609 pnp_port_start(pdev, 0) + 0x10c != pnp_port_start(pdev, 2)) {
610 kfree(cfg);
611 snd_printk(KERN_ERR "PnP configure failure (wrong ports)\n");
612 return -ENOENT;
613 }
614 port[dev] = pnp_port_start(pdev, 0);
615 dma1[dev] = pnp_dma(pdev, 0);
616 if (dma2[dev] >= 0)
617 dma2[dev] = pnp_dma(pdev, 1);
618 irq[dev] = pnp_irq(pdev, 0);
619 snd_printdd("isapnp IW: sb port=0x%lx, gf1 port=0x%lx, codec port=0x%lx\n",
620 pnp_port_start(pdev, 0),
621 pnp_port_start(pdev, 1),
622 pnp_port_start(pdev, 2));
623 snd_printdd("isapnp IW: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
624#ifdef SNDRV_STB
625 /* Tone Control initialization */
626 pdev = iwcard->devtc;
627 pnp_init_resource_table(cfg);
628 if (port_tc[dev] != SNDRV_AUTO_PORT)
629 pnp_resource_change(&cfg->port_resource[0], port_tc[dev], 1);
630 if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
631 snd_printk(KERN_ERR "InterWave - ToneControl - the requested resources are invalid, using auto config\n");
632 err = pnp_activate_dev(pdev);
633 if (err < 0) {
634 kfree(cfg);
635 snd_printk(KERN_ERR "InterWave ToneControl PnP configure failure (out of resources?)\n");
636 return err;
637 }
638 port_tc[dev] = pnp_port_start(pdev, 0);
639 snd_printdd("isapnp IW: tone control port=0x%lx\n", port_tc[dev]);
640#endif
641 kfree(cfg);
642 return 0;
643}
644#endif /* CONFIG_PNP */
645
646static void snd_interwave_free(snd_card_t *card)
647{
648 struct snd_interwave *iwcard = (struct snd_interwave *)card->private_data;
649
650 if (iwcard == NULL)
651 return;
652#ifdef SNDRV_STB
653 if (iwcard->i2c_res) {
654 release_resource(iwcard->i2c_res);
655 kfree_nocheck(iwcard->i2c_res);
656 }
657#endif
658 if (iwcard->irq >= 0)
659 free_irq(iwcard->irq, (void *)iwcard);
660}
661
662static int __devinit snd_interwave_probe(int dev, struct pnp_card_link *pcard,
663 const struct pnp_card_device_id *pid)
664{
665 static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
666 static int possible_dmas[] = {0, 1, 3, 5, 6, 7, -1};
667 int xirq, xdma1, xdma2;
668 snd_card_t *card;
669 struct snd_interwave *iwcard;
670 cs4231_t *cs4231;
671 snd_gus_card_t *gus;
672#ifdef SNDRV_STB
673 snd_i2c_bus_t *i2c_bus;
674#endif
675 snd_pcm_t *pcm;
676 char *str;
677 int err;
678
679 card = snd_card_new(index[dev], id[dev], THIS_MODULE,
680 sizeof(struct snd_interwave));
681 if (card == NULL)
682 return -ENOMEM;
683 iwcard = (struct snd_interwave *)card->private_data;
684 iwcard->card = card;
685 iwcard->irq = -1;
686 card->private_free = snd_interwave_free;
687#ifdef CONFIG_PNP
688 if (isapnp[dev]) {
689 if (snd_interwave_pnp(dev, iwcard, pcard, pid)) {
690 snd_card_free(card);
691 return -ENODEV;
692 }
693 snd_card_set_dev(card, &pcard->card->dev);
694 }
695#endif
696 xirq = irq[dev];
697 if (xirq == SNDRV_AUTO_IRQ) {
698 if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
699 snd_card_free(card);
700 snd_printk("unable to find a free IRQ\n");
701 return -EBUSY;
702 }
703 }
704 xdma1 = dma1[dev];
705 if (xdma1 == SNDRV_AUTO_DMA) {
706 if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
707 snd_card_free(card);
708 snd_printk("unable to find a free DMA1\n");
709 return -EBUSY;
710 }
711 }
712 xdma2 = dma2[dev];
713 if (xdma2 == SNDRV_AUTO_DMA) {
714 if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
715 snd_card_free(card);
716 snd_printk("unable to find a free DMA2\n");
717 return -EBUSY;
718 }
719 }
720
721 if ((err = snd_gus_create(card,
722 port[dev],
723 -xirq, xdma1, xdma2,
724 0, 32,
725 pcm_channels[dev], effect[dev], &gus)) < 0) {
726 snd_card_free(card);
727 return err;
728 }
729 if ((err = snd_interwave_detect(iwcard, gus, dev
730#ifdef SNDRV_STB
731 , &i2c_bus
732#endif
733 )) < 0) {
734 snd_card_free(card);
735 return err;
736 }
737 iwcard->gus_status_reg = gus->gf1.reg_irqstat;
738 iwcard->pcm_status_reg = gus->gf1.port + 0x10c + 2;
739
740 snd_interwave_init(dev, gus);
741 snd_interwave_detect_memory(gus);
742 if ((err = snd_gus_initialize(gus)) < 0) {
743 snd_card_free(card);
744 return err;
745 }
746
747 if (request_irq(xirq, snd_interwave_interrupt, SA_INTERRUPT, "InterWave", (void *)iwcard)) {
748 snd_card_free(card);
749 snd_printk("unable to grab IRQ %d\n", xirq);
750 return -EBUSY;
751 }
752 iwcard->irq = xirq;
753
754 if ((err = snd_cs4231_create(card,
755 gus->gf1.port + 0x10c, -1, xirq,
756 xdma2 < 0 ? xdma1 : xdma2, xdma1,
757 CS4231_HW_INTERWAVE,
758 CS4231_HWSHARE_IRQ |
759 CS4231_HWSHARE_DMA1 |
760 CS4231_HWSHARE_DMA2,
761 &cs4231)) < 0) {
762 snd_card_free(card);
763 return err;
764 }
765 if ((err = snd_cs4231_pcm(cs4231, 0, &pcm)) < 0) {
766 snd_card_free(card);
767 return err;
768 }
769 sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
770 strcat(pcm->name, " (codec)");
771 if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) {
772 snd_card_free(card);
773 return err;
774 }
775 if ((err = snd_cs4231_mixer(cs4231)) < 0) {
776 snd_card_free(card);
777 return err;
778 }
779 if (pcm_channels[dev] > 0) {
780 if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) {
781 snd_card_free(card);
782 return err;
783 }
784 }
785 if ((err = snd_interwave_mixer(cs4231)) < 0) {
786 snd_card_free(card);
787 return err;
788 }
789#ifdef SNDRV_STB
790 {
791 snd_ctl_elem_id_t id1, id2;
792 memset(&id1, 0, sizeof(id1));
793 memset(&id2, 0, sizeof(id2));
794 id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
795 strcpy(id1.name, "Master Playback Switch");
796 strcpy(id2.name, id1.name);
797 id2.index = 1;
798 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) {
799 snd_card_free(card);
800 return err;
801 }
802 strcpy(id1.name, "Master Playback Volume");
803 strcpy(id2.name, id1.name);
804 if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) {
805 snd_card_free(card);
806 return err;
807 }
808 if ((err = snd_tea6330t_update_mixer(card, i2c_bus, 0, 1)) < 0) {
809 snd_card_free(card);
810 return err;
811 }
812 }
813#endif
814
815 gus->uart_enable = midi[dev];
816 if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) {
817 snd_card_free(card);
818 return err;
819 }
820
821#ifndef SNDRV_STB
822 str = "AMD InterWave";
823 if (gus->gf1.rom_banks == 1 && gus->gf1.rom_present == 8)
824 str = "Dynasonic 3-D";
825#else
826 str = "InterWave STB";
827#endif
828 strcpy(card->driver, str);
829 strcpy(card->shortname, str);
830 sprintf(card->longname, "%s at 0x%lx, irq %i, dma %d",
831 str,
832 gus->gf1.port,
833 xirq,
834 xdma1);
835 if (xdma2 >= 0)
836 sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
837
838 if ((err = snd_card_register(card)) < 0) {
839 snd_card_free(card);
840 return err;
841 }
842
843 iwcard->cs4231 = cs4231;
844 iwcard->gus = gus;
845 if (pcard)
846 pnp_set_card_drvdata(pcard, card);
847 else
848 snd_interwave_legacy[dev++] = card;
849 return 0;
850}
851
852static int __devinit snd_interwave_probe_legacy_port(unsigned long xport)
853{
854 static int dev;
855 int res;
856
857 for ( ; dev < SNDRV_CARDS; dev++) {
858 if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT)
859 continue;
860#ifdef CONFIG_PNP
861 if (isapnp[dev])
862 continue;
863#endif
864 port[dev] = xport;
865 res = snd_interwave_probe(dev, NULL, NULL);
866 if (res < 0)
867 port[dev] = SNDRV_AUTO_PORT;
868 return res;
869 }
870 return -ENODEV;
871}
872
873#ifdef CONFIG_PNP
874
875static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *card,
876 const struct pnp_card_device_id *id)
877{
878 static int dev;
879 int res;
880
881 for ( ; dev < SNDRV_CARDS; dev++) {
882 if (!enable[dev] || !isapnp[dev])
883 continue;
884 res = snd_interwave_probe(dev, card, id);
885 if (res < 0)
886 return res;
887 dev++;
888 return 0;
889 }
890
891 return -ENODEV;
892}
893
894static void __devexit snd_interwave_pnp_remove(struct pnp_card_link * pcard)
895{
896 snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
897
898 snd_card_disconnect(card);
899 snd_card_free_in_thread(card);
900}
901
902static struct pnp_card_driver interwave_pnpc_driver = {
903 .flags = PNP_DRIVER_RES_DISABLE,
904 .name = "interwave",
905 .id_table = snd_interwave_pnpids,
906 .probe = snd_interwave_pnp_detect,
907 .remove = __devexit_p(snd_interwave_pnp_remove),
908};
909
910#endif /* CONFIG_PNP */
911
912static int __init alsa_card_interwave_init(void)
913{
914 int cards = 0, i;
915 static long possible_ports[] = {0x210, 0x220, 0x230, 0x240, 0x250, 0x260, -1};
916 int dev;
917
918 for (dev = 0; dev < SNDRV_CARDS; dev++) {
919 if (!enable[dev] || port[dev] == SNDRV_AUTO_PORT)
920 continue;
921#ifdef CONFIG_PNP
922 if (isapnp[dev])
923 continue;
924#endif
925 if (!snd_interwave_probe(dev, NULL, NULL)) {
926 cards++;
927 continue;
928 }
929#ifdef MODULE
930 printk(KERN_ERR "InterWave soundcard #%i not found at 0x%lx or device busy\n", dev, port[dev]);
931#endif
932 }
933 /* legacy auto configured cards */
934 i = snd_legacy_auto_probe(possible_ports, snd_interwave_probe_legacy_port);
935 if (i > 0)
936 cards += i;
937#ifdef CONFIG_PNP
938 /* ISA PnP cards */
939 i = pnp_register_card_driver(&interwave_pnpc_driver);
940 if (i > 0)
941 cards += i;
942#endif
943
944 if (!cards) {
945#ifdef CONFIG_PNP
946 pnp_unregister_card_driver(&interwave_pnpc_driver);
947#endif
948#ifdef MODULE
949 printk(KERN_ERR "InterWave soundcard not found or device busy\n");
950#endif
951 return -ENODEV;
952 }
953 return 0;
954}
955
956static void __exit alsa_card_interwave_exit(void)
957{
958 int dev;
959
960#ifdef CONFIG_PNP
961 /* PnP cards first */
962 pnp_unregister_card_driver(&interwave_pnpc_driver);
963#endif
964 for (dev = 0; dev < SNDRV_CARDS; dev++)
965 snd_card_free(snd_interwave_legacy[dev]);
966}
967
968module_init(alsa_card_interwave_init)
969module_exit(alsa_card_interwave_exit)