aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-10-30 07:17:17 -0400
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:29:13 -0500
commite5723b41abe559bafc52591dcf8ee19cc131d3a1 (patch)
treea1d035132ae1354c43eb9fccf60c9668e0abb266 /sound/isa
parent05c1afe75fcebf456017ec186811cf1599f4360e (diff)
[ALSA] Remove sequencer instrument layer
Remove sequencer instrument layer from the tree. This mechanism hasn't been used much with the actual devices. The only reasonable user was OPL3 loader, and now it was rewritten to use hwdep instead. So, let's remove the rest of rotten codes. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/isa')
-rw-r--r--sound/isa/gus/Makefile12
-rw-r--r--sound/isa/gus/gus_main.c23
-rw-r--r--sound/isa/gus/gus_sample.c165
-rw-r--r--sound/isa/gus/gus_simple.c634
-rw-r--r--sound/isa/gus/gus_synth.c314
5 files changed, 0 insertions, 1148 deletions
diff --git a/sound/isa/gus/Makefile b/sound/isa/gus/Makefile
index df3d59f25f5e..6cd4ee03754a 100644
--- a/sound/isa/gus/Makefile
+++ b/sound/isa/gus/Makefile
@@ -9,7 +9,6 @@ snd-gus-lib-objs := gus_main.o \
9 gus_pcm.o gus_mixer.o \ 9 gus_pcm.o gus_mixer.o \
10 gus_uart.o \ 10 gus_uart.o \
11 gus_reset.o 11 gus_reset.o
12snd-gus-synth-objs := gus_synth.o gus_sample.o gus_simple.o gus_instr.o
13 12
14snd-gusclassic-objs := gusclassic.o 13snd-gusclassic-objs := gusclassic.o
15snd-gusextreme-objs := gusextreme.o 14snd-gusextreme-objs := gusextreme.o
@@ -17,20 +16,9 @@ snd-gusmax-objs := gusmax.o
17snd-interwave-objs := interwave.o 16snd-interwave-objs := interwave.o
18snd-interwave-stb-objs := interwave-stb.o 17snd-interwave-stb-objs := interwave-stb.o
19 18
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 19# Toplevel Module Dependency
29obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o 20obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o
30obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o 21obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o
31obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o 22obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o
32obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o 23obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o
33obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o 24obj-$(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_main.c b/sound/isa/gus/gus_main.c
index b14d5d6d9a32..e4453e5e5c23 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -104,12 +104,6 @@ static int snd_gus_free(struct snd_gus_card *gus)
104{ 104{
105 if (gus->gf1.res_port2 == NULL) 105 if (gus->gf1.res_port2 == NULL)
106 goto __hw_end; 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); 107 snd_gf1_stop(gus);
114 snd_gus_init_dma_irq(gus, 0); 108 snd_gus_init_dma_irq(gus, 0);
115 __hw_end: 109 __hw_end:
@@ -408,14 +402,6 @@ static int snd_gus_check_version(struct snd_gus_card * gus)
408 return 0; 402 return 0;
409} 403}
410 404
411#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
412static void snd_gus_seq_dev_free(struct snd_seq_device *seq_dev)
413{
414 struct snd_gus_card *gus = seq_dev->private_data;
415 gus->seq_dev = NULL;
416}
417#endif
418
419int snd_gus_initialize(struct snd_gus_card *gus) 405int snd_gus_initialize(struct snd_gus_card *gus)
420{ 406{
421 int err; 407 int err;
@@ -430,15 +416,6 @@ int snd_gus_initialize(struct snd_gus_card *gus)
430 } 416 }
431 if ((err = snd_gus_init_dma_irq(gus, 1)) < 0) 417 if ((err = snd_gus_init_dma_irq(gus, 1)) < 0)
432 return err; 418 return err;
433#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
434 if (snd_seq_device_new(gus->card, 1, SNDRV_SEQ_DEV_ID_GUS,
435 sizeof(struct snd_gus_card *), &gus->seq_dev) >= 0) {
436 strcpy(gus->seq_dev->name, "GUS");
437 *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(gus->seq_dev) = gus;
438 gus->seq_dev->private_data = gus;
439 gus->seq_dev->private_free = snd_gus_seq_dev_free;
440 }
441#endif
442 snd_gf1_start(gus); 419 snd_gf1_start(gus);
443 gus->initialized = 1; 420 gus->initialized = 1;
444 return 0; 421 return 0;
diff --git a/sound/isa/gus/gus_sample.c b/sound/isa/gus/gus_sample.c
deleted file mode 100644
index cba0829a7106..000000000000
--- a/sound/isa/gus/gus_sample.c
+++ /dev/null
@@ -1,165 +0,0 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Sample support
3 * Copyright (c) by Jaroslav Kysela <perex@perex.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(struct snd_gus_card * gus, struct snd_gus_voice * v)
32{
33 struct snd_seq_kinstr *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(struct snd_seq_event *ev, struct snd_gus_port *p,
57 struct snd_gus_voice *v)
58{
59 if (v->sample_ops && v->sample_ops->sample_stop)
60 v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
61 v->instr.std = ev->data.sample.param.sample.std;
62 if (v->instr.std & 0xff000000) { /* private instrument */
63 v->instr.std &= 0x00ffffff;
64 v->instr.std |= (unsigned int)ev->source.client << 24;
65 }
66 v->instr.bank = ev->data.sample.param.sample.bank;
67 v->instr.prg = ev->data.sample.param.sample.prg;
68 select_instrument(p->gus, v);
69}
70
71static void event_cluster(struct snd_seq_event *ev, struct snd_gus_port *p,
72 struct snd_gus_voice *v)
73{
74 if (v->sample_ops && v->sample_ops->sample_stop)
75 v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
76 v->instr.cluster = ev->data.sample.param.cluster.cluster;
77 select_instrument(p->gus, v);
78}
79
80static void event_start(struct snd_seq_event *ev, struct snd_gus_port *p,
81 struct snd_gus_voice *v)
82{
83 if (v->sample_ops && v->sample_ops->sample_start)
84 v->sample_ops->sample_start(p->gus, v, ev->data.sample.param.position);
85}
86
87static void event_stop(struct snd_seq_event *ev, struct snd_gus_port *p,
88 struct snd_gus_voice *v)
89{
90 if (v->sample_ops && v->sample_ops->sample_stop)
91 v->sample_ops->sample_stop(p->gus, v, ev->data.sample.param.stop_mode);
92}
93
94static void event_freq(struct snd_seq_event *ev, struct snd_gus_port *p,
95 struct snd_gus_voice *v)
96{
97 if (v->sample_ops && v->sample_ops->sample_freq)
98 v->sample_ops->sample_freq(p->gus, v, ev->data.sample.param.frequency);
99}
100
101static void event_volume(struct snd_seq_event *ev, struct snd_gus_port *p,
102 struct snd_gus_voice *v)
103{
104 if (v->sample_ops && v->sample_ops->sample_volume)
105 v->sample_ops->sample_volume(p->gus, v, &ev->data.sample.param.volume);
106}
107
108static void event_loop(struct snd_seq_event *ev, struct snd_gus_port *p,
109 struct snd_gus_voice *v)
110{
111 if (v->sample_ops && v->sample_ops->sample_loop)
112 v->sample_ops->sample_loop(p->gus, v, &ev->data.sample.param.loop);
113}
114
115static void event_position(struct snd_seq_event *ev, struct snd_gus_port *p,
116 struct snd_gus_voice *v)
117{
118 if (v->sample_ops && v->sample_ops->sample_pos)
119 v->sample_ops->sample_pos(p->gus, v, ev->data.sample.param.position);
120}
121
122static void event_private1(struct snd_seq_event *ev, struct snd_gus_port *p,
123 struct snd_gus_voice *v)
124{
125 if (v->sample_ops && v->sample_ops->sample_private1)
126 v->sample_ops->sample_private1(p->gus, v, (unsigned char *)&ev->data.sample.param.raw8);
127}
128
129typedef void (gus_sample_event_handler_t)(struct snd_seq_event *ev,
130 struct snd_gus_port *p,
131 struct snd_gus_voice *v);
132static gus_sample_event_handler_t *gus_sample_event_handlers[9] = {
133 event_sample,
134 event_cluster,
135 event_start,
136 event_stop,
137 event_freq,
138 event_volume,
139 event_loop,
140 event_position,
141 event_private1
142};
143
144void snd_gus_sample_event(struct snd_seq_event *ev, struct snd_gus_port *p)
145{
146 int idx, voice;
147 struct snd_gus_card *gus = p->gus;
148 struct snd_gus_voice *v;
149 unsigned long flags;
150
151 idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
152 if (idx < 0 || idx > 8)
153 return;
154 for (voice = 0; voice < 32; voice++) {
155 v = &gus->gf1.voices[voice];
156 if (v->use && v->client == ev->source.client &&
157 v->port == ev->source.port &&
158 v->index == ev->data.sample.channel) {
159 spin_lock_irqsave(&gus->event_lock, flags);
160 gus_sample_event_handlers[idx](ev, p, v);
161 spin_unlock_irqrestore(&gus->event_lock, flags);
162 return;
163 }
164 }
165}
diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c
deleted file mode 100644
index 39d121e2c8c4..000000000000
--- a/sound/isa/gus/gus_simple.c
+++ /dev/null
@@ -1,634 +0,0 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Simple instrument handlers
3 * Copyright (c) by Jaroslav Kysela <perex@perex.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(struct snd_gus_card *gus, struct snd_gus_voice *voice);
33static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice);
34static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice);
35
36static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position);
37static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode);
38static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq);
39static void sample_volume(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume);
40static void sample_loop(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop);
41static void sample_pos(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position);
42static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data);
43
44static struct snd_gus_sample_ops 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(struct snd_gus_card *gus, struct snd_gus_voice *voice, int wait);
57static void note_wait(struct snd_gus_card *gus, struct snd_gus_voice *voice);
58static void note_off(struct snd_gus_card *gus, struct snd_gus_voice *voice);
59static void note_volume(struct snd_gus_card *card, struct snd_gus_voice *voice);
60static void note_pitchbend(struct snd_gus_card *card, struct snd_gus_voice *voice);
61static void note_vibrato(struct snd_gus_card *card, struct snd_gus_voice *voice);
62static void note_tremolo(struct snd_gus_card *card, struct snd_gus_voice *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(struct snd_gus_card *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(struct snd_gus_card *card, struct snd_gus_voice *voice);
87static void do_pan_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice);
88
89/*
90 *
91 */
92
93static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *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(struct snd_gus_card *gus, struct snd_gus_voice *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(struct snd_gus_card *gus, struct snd_gus_voice *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(struct snd_gus_card *gus, struct snd_gus_voice *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(struct snd_gus_card *gus, struct snd_gus_voice *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(struct snd_gus_card *gus, struct snd_gus_voice *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(struct snd_gus_card *gus, struct snd_gus_voice *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 struct simple_instrument *simple;
316 struct snd_seq_kinstr *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(struct snd_gus_card *gus, struct snd_gus_voice *voice, int 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(struct snd_gus_card *gus, struct snd_gus_voice *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(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *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(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop)
475{
476 unsigned long flags;
477 int w_16 = voice->control & 0x04;
478 unsigned int begin, addr_start, addr_end;
479 struct simple_instrument *simple;
480 struct snd_seq_kinstr *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(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position)
504{
505 unsigned long flags;
506 int w_16 = voice->control & 0x04;
507 unsigned int begin, addr;
508 struct simple_instrument *simple;
509 struct snd_seq_kinstr *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(struct snd_gus_card *card, struct snd_gus_voice *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(struct snd_gus_voice *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
deleted file mode 100644
index 2c2051782aa2..000000000000
--- a/sound/isa/gus/gus_synth.c
+++ /dev/null
@@ -1,314 +0,0 @@
1/*
2 * Routines for Gravis UltraSound soundcards - Synthesizer
3 * Copyright (c) by Jaroslav Kysela <perex@perex.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@perex.cz>");
30MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer");
31MODULE_LICENSE("GPL");
32
33/*
34 *
35 */
36
37static void snd_gus_synth_free_voices(struct snd_gus_card * gus, int client, int port)
38{
39 int idx;
40 struct snd_gus_voice * 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, struct snd_seq_port_subscribe *info)
50{
51 struct snd_gus_port * port = private_data;
52 struct snd_gus_card * gus = port->gus;
53 struct snd_gus_voice * voice;
54 unsigned int idx;
55
56 if (info->voices > 32)
57 return -EINVAL;
58 mutex_lock(&gus->register_mutex);
59 if (!snd_gus_use_inc(gus)) {
60 mutex_unlock(&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 mutex_unlock(&gus->register_mutex);
69 return -EBUSY;
70 }
71 voice->index = idx;
72 }
73 mutex_unlock(&gus->register_mutex);
74 return 0;
75}
76
77static int snd_gus_synth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
78{
79 struct snd_gus_port * port = private_data;
80 struct snd_gus_card * gus = port->gus;
81
82 mutex_lock(&gus->register_mutex);
83 snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
84 snd_gus_use_dec(gus);
85 mutex_unlock(&gus->register_mutex);
86 return 0;
87}
88
89/*
90 *
91 */
92
93static void snd_gus_synth_free_private_instruments(struct snd_gus_port *p, int client)
94{
95 struct snd_seq_instr_header 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
102static int snd_gus_synth_event_input(struct snd_seq_event *ev, int direct,
103 void *private_data, int atomic, int hop)
104{
105 struct snd_gus_port * p = private_data;
106
107 snd_assert(p != NULL, return -EINVAL);
108 if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
109 ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
110 snd_gus_sample_event(ev, p);
111 return 0;
112 }
113 if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
114 ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
115 if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
116 snd_gus_synth_free_private_instruments(p, ev->data.addr.client);
117 return 0;
118 }
119 }
120 if (direct) {
121 if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
122 snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops,
123 p->gus->gf1.ilist,
124 ev,
125 p->gus->gf1.seq_client,
126 atomic, hop);
127 return 0;
128 }
129 }
130 return 0;
131}
132
133static void snd_gus_synth_instr_notify(void *private_data,
134 struct snd_seq_kinstr *instr,
135 int what)
136{
137 unsigned int idx;
138 struct snd_gus_card *gus = private_data;
139 struct snd_gus_voice *pvoice;
140 unsigned long flags;
141
142 spin_lock_irqsave(&gus->event_lock, flags);
143 for (idx = 0; idx < 32; idx++) {
144 pvoice = &gus->gf1.voices[idx];
145 if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
146 if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
147 pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY);
148 } else {
149 snd_gf1_stop_voice(gus, pvoice->number);
150 pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
151 }
152 }
153 }
154 spin_unlock_irqrestore(&gus->event_lock, flags);
155}
156
157/*
158 *
159 */
160
161static void snd_gus_synth_free_port(void *private_data)
162{
163 struct snd_gus_port * p = private_data;
164
165 if (p)
166 snd_midi_channel_free_set(p->chset);
167}
168
169static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx)
170{
171 struct snd_gus_port * p;
172 struct snd_seq_port_callback callbacks;
173 char name[32];
174 int result;
175
176 p = &gus->gf1.seq_ports[idx];
177 p->chset = snd_midi_channel_alloc_set(16);
178 if (p->chset == NULL)
179 return -ENOMEM;
180 p->chset->private_data = p;
181 p->gus = gus;
182 p->client = gus->gf1.seq_client;
183
184 memset(&callbacks, 0, sizeof(callbacks));
185 callbacks.owner = THIS_MODULE;
186 callbacks.use = snd_gus_synth_use;
187 callbacks.unuse = snd_gus_synth_unuse;
188 callbacks.event_input = snd_gus_synth_event_input;
189 callbacks.private_free = snd_gus_synth_free_port;
190 callbacks.private_data = p;
191
192 sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx);
193 p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client,
194 &callbacks,
195 SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
196 SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
197 SNDRV_SEQ_PORT_TYPE_SYNTH |
198 SNDRV_SEQ_PORT_TYPE_HARDWARE |
199 SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
200 16, 0,
201 name);
202 if (p->chset->port < 0) {
203 result = p->chset->port;
204 snd_gus_synth_free_port(p);
205 return result;
206 }
207 p->port = p->chset->port;
208 return 0;
209}
210
211/*
212 *
213 */
214
215static int snd_gus_synth_new_device(struct snd_seq_device *dev)
216{
217 struct snd_gus_card *gus;
218 int client, i;
219 struct snd_seq_port_subscribe sub;
220 struct snd_iwffff_ops *iwops;
221 struct snd_gf1_ops *gf1ops;
222 struct snd_simple_ops *simpleops;
223
224 gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
225 if (gus == NULL)
226 return -EINVAL;
227
228 mutex_init(&gus->register_mutex);
229 gus->gf1.seq_client = -1;
230
231 /* allocate new client */
232 client = gus->gf1.seq_client =
233 snd_seq_create_kernel_client(gus->card, 1, gus->interwave ?
234 "AMD InterWave" : "GF1");
235 if (client < 0)
236 return client;
237
238 for (i = 0; i < 4; i++)
239 snd_gus_synth_create_port(gus, i);
240
241 gus->gf1.ilist = snd_seq_instr_list_new();
242 if (gus->gf1.ilist == NULL) {
243 snd_seq_delete_kernel_client(client);
244 gus->gf1.seq_client = -1;
245 return -ENOMEM;
246 }
247 gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
248
249 simpleops = &gus->gf1.simple_ops;
250 snd_seq_simple_init(simpleops, gus, NULL);
251 simpleops->put_sample = snd_gus_simple_put_sample;
252 simpleops->get_sample = snd_gus_simple_get_sample;
253 simpleops->remove_sample = snd_gus_simple_remove_sample;
254 simpleops->notify = snd_gus_synth_instr_notify;
255
256 gf1ops = &gus->gf1.gf1_ops;
257 snd_seq_gf1_init(gf1ops, gus, &simpleops->kops);
258 gf1ops->put_sample = snd_gus_gf1_put_sample;
259 gf1ops->get_sample = snd_gus_gf1_get_sample;
260 gf1ops->remove_sample = snd_gus_gf1_remove_sample;
261 gf1ops->notify = snd_gus_synth_instr_notify;
262
263 iwops = &gus->gf1.iwffff_ops;
264 snd_seq_iwffff_init(iwops, gus, &gf1ops->kops);
265 iwops->put_sample = snd_gus_iwffff_put_sample;
266 iwops->get_sample = snd_gus_iwffff_get_sample;
267 iwops->remove_sample = snd_gus_iwffff_remove_sample;
268 iwops->notify = snd_gus_synth_instr_notify;
269
270 memset(&sub, 0, sizeof(sub));
271 sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
272 sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
273 sub.dest.client = client;
274 sub.dest.port = 0;
275 snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
276
277 return 0;
278}
279
280static int snd_gus_synth_delete_device(struct snd_seq_device *dev)
281{
282 struct snd_gus_card *gus;
283
284 gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
285 if (gus == NULL)
286 return -EINVAL;
287
288 if (gus->gf1.seq_client >= 0) {
289 snd_seq_delete_kernel_client(gus->gf1.seq_client);
290 gus->gf1.seq_client = -1;
291 }
292 if (gus->gf1.ilist)
293 snd_seq_instr_list_free(&gus->gf1.ilist);
294 return 0;
295}
296
297static int __init alsa_gus_synth_init(void)
298{
299 static struct snd_seq_dev_ops ops = {
300 snd_gus_synth_new_device,
301 snd_gus_synth_delete_device
302 };
303
304 return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops,
305 sizeof(struct snd_gus_card *));
306}
307
308static void __exit alsa_gus_synth_exit(void)
309{
310 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS);
311}
312
313module_init(alsa_gus_synth_init)
314module_exit(alsa_gus_synth_exit)