2 * Routines for Gravis UltraSound soundcards - Synthesizer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
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.
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.
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
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>
29 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
30 MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer");
31 MODULE_LICENSE("GPL");
37 static void snd_gus_synth_free_voices(struct snd_gus_card
* gus
, int client
, int port
)
40 struct snd_gus_voice
* voice
;
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
);
49 static int snd_gus_synth_use(void *private_data
, struct snd_seq_port_subscribe
*info
)
51 struct snd_gus_port
* port
= private_data
;
52 struct snd_gus_card
* gus
= port
->gus
;
53 struct snd_gus_voice
* voice
;
56 if (info
->voices
> 32)
58 mutex_lock(&gus
->register_mutex
);
59 if (!snd_gus_use_inc(gus
)) {
60 mutex_unlock(&gus
->register_mutex
);
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
);
66 snd_gus_synth_free_voices(gus
, info
->sender
.client
, info
->sender
.port
);
68 mutex_unlock(&gus
->register_mutex
);
73 mutex_unlock(&gus
->register_mutex
);
77 static int snd_gus_synth_unuse(void *private_data
, struct snd_seq_port_subscribe
*info
)
79 struct snd_gus_port
* port
= private_data
;
80 struct snd_gus_card
* gus
= port
->gus
;
82 mutex_lock(&gus
->register_mutex
);
83 snd_gus_synth_free_voices(gus
, info
->sender
.client
, info
->sender
.port
);
85 mutex_unlock(&gus
->register_mutex
);
93 static void snd_gus_synth_free_private_instruments(struct snd_gus_port
*p
, int client
)
95 struct snd_seq_instr_header ifree
;
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);
102 static int snd_gus_synth_event_input(struct snd_seq_event
*ev
, int direct
,
103 void *private_data
, int atomic
, int hop
)
105 struct snd_gus_port
* p
= private_data
;
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
);
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
);
121 if (ev
->type
>= SNDRV_SEQ_EVENT_INSTR_BEGIN
) {
122 snd_seq_instr_event(&p
->gus
->gf1
.iwffff_ops
.kops
,
125 p
->gus
->gf1
.seq_client
,
133 static void snd_gus_synth_instr_notify(void *private_data
,
134 struct snd_seq_kinstr
*instr
,
138 struct snd_gus_card
*gus
= private_data
;
139 struct snd_gus_voice
*pvoice
;
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
);
149 snd_gf1_stop_voice(gus
, pvoice
->number
);
150 pvoice
->flags
&= ~SNDRV_GF1_VFLG_RUNNING
;
154 spin_unlock_irqrestore(&gus
->event_lock
, flags
);
161 static void snd_gus_synth_free_port(void *private_data
)
163 struct snd_gus_port
* p
= private_data
;
166 snd_midi_channel_free_set(p
->chset
);
169 static int snd_gus_synth_create_port(struct snd_gus_card
* gus
, int idx
)
171 struct snd_gus_port
* p
;
172 struct snd_seq_port_callback callbacks
;
176 p
= &gus
->gf1
.seq_ports
[idx
];
177 p
->chset
= snd_midi_channel_alloc_set(16);
178 if (p
->chset
== NULL
)
180 p
->chset
->private_data
= p
;
182 p
->client
= gus
->gf1
.seq_client
;
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
;
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
,
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
,
202 if (p
->chset
->port
< 0) {
203 result
= p
->chset
->port
;
204 snd_gus_synth_free_port(p
);
207 p
->port
= p
->chset
->port
;
215 static int snd_gus_synth_new_device(struct snd_seq_device
*dev
)
217 struct snd_gus_card
*gus
;
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
;
224 gus
= *(struct snd_gus_card
**)SNDRV_SEQ_DEVICE_ARGPTR(dev
);
228 mutex_init(&gus
->register_mutex
);
229 gus
->gf1
.seq_client
= -1;
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");
238 for (i
= 0; i
< 4; i
++)
239 snd_gus_synth_create_port(gus
, i
);
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;
247 gus
->gf1
.ilist
->flags
= SNDRV_SEQ_INSTR_FLG_DIRECT
;
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
;
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
;
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
;
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
;
275 snd_seq_kernel_client_ctl(client
, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT
, &sub
);
280 static int snd_gus_synth_delete_device(struct snd_seq_device
*dev
)
282 struct snd_gus_card
*gus
;
284 gus
= *(struct snd_gus_card
**)SNDRV_SEQ_DEVICE_ARGPTR(dev
);
288 if (gus
->gf1
.seq_client
>= 0) {
289 snd_seq_delete_kernel_client(gus
->gf1
.seq_client
);
290 gus
->gf1
.seq_client
= -1;
293 snd_seq_instr_list_free(&gus
->gf1
.ilist
);
297 static int __init
alsa_gus_synth_init(void)
299 static struct snd_seq_dev_ops ops
= {
300 snd_gus_synth_new_device
,
301 snd_gus_synth_delete_device
304 return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS
, &ops
,
305 sizeof(struct snd_gus_card
*));
308 static void __exit
alsa_gus_synth_exit(void)
310 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS
);
313 module_init(alsa_gus_synth_init
)
314 module_exit(alsa_gus_synth_exit
)