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(snd_gus_card_t
* gus
, int client
, int port
)
40 snd_gus_voice_t
* 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
, snd_seq_port_subscribe_t
*info
)
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
;
56 if (info
->voices
> 32)
58 down(&gus
->register_mutex
);
59 if (!snd_gus_use_inc(gus
)) {
60 up(&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 up(&gus
->register_mutex
);
73 up(&gus
->register_mutex
);
77 static int snd_gus_synth_unuse(void *private_data
, snd_seq_port_subscribe_t
*info
)
79 snd_gus_port_t
* port
= (snd_gus_port_t
*)private_data
;
80 snd_gus_card_t
* gus
= port
->gus
;
82 down(&gus
->register_mutex
);
83 snd_gus_synth_free_voices(gus
, info
->sender
.client
, info
->sender
.port
);
85 up(&gus
->register_mutex
);
93 static void snd_gus_synth_free_private_instruments(snd_gus_port_t
*p
, int client
)
95 snd_seq_instr_header_t 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 int snd_gus_synth_event_input(snd_seq_event_t
*ev
, int direct
, void *private_data
, int atomic
, int hop
)
104 snd_gus_port_t
* p
= (snd_gus_port_t
*) private_data
;
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
);
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
);
120 if (ev
->type
>= SNDRV_SEQ_EVENT_INSTR_BEGIN
) {
121 snd_seq_instr_event(&p
->gus
->gf1
.iwffff_ops
.kops
,
124 p
->gus
->gf1
.seq_client
,
132 static void snd_gus_synth_instr_notify(void *private_data
,
133 snd_seq_kinstr_t
*instr
,
137 snd_gus_card_t
*gus
= private_data
;
138 snd_gus_voice_t
*pvoice
;
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
);
148 snd_gf1_stop_voice(gus
, pvoice
->number
);
149 pvoice
->flags
&= ~SNDRV_GF1_VFLG_RUNNING
;
153 spin_unlock_irqrestore(&gus
->event_lock
, flags
);
160 static void snd_gus_synth_free_port(void *private_data
)
162 snd_gus_port_t
* p
= (snd_gus_port_t
*)private_data
;
165 snd_midi_channel_free_set(p
->chset
);
168 static int snd_gus_synth_create_port(snd_gus_card_t
* gus
, int idx
)
171 snd_seq_port_callback_t callbacks
;
175 p
= &gus
->gf1
.seq_ports
[idx
];
176 p
->chset
= snd_midi_channel_alloc_set(16);
177 if (p
->chset
== NULL
)
179 p
->chset
->private_data
= p
;
181 p
->client
= gus
->gf1
.seq_client
;
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
;
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
,
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
,
199 if (p
->chset
->port
< 0) {
200 result
= p
->chset
->port
;
201 snd_gus_synth_free_port(p
);
204 p
->port
= p
->chset
->port
;
212 static int snd_gus_synth_new_device(snd_seq_device_t
*dev
)
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
;
223 gus
= *(snd_gus_card_t
**)SNDRV_SEQ_DEVICE_ARGPTR(dev
);
227 init_MUTEX(&gus
->register_mutex
);
228 gus
->gf1
.seq_client
= -1;
230 cinfo
= kmalloc(sizeof(*cinfo
), GFP_KERNEL
);
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
);
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
);
253 for (i
= 0; i
< 4; i
++)
254 snd_gus_synth_create_port(gus
, i
);
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;
262 gus
->gf1
.ilist
->flags
= SNDRV_SEQ_INSTR_FLG_DIRECT
;
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
;
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
;
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
;
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
;
290 snd_seq_kernel_client_ctl(client
, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT
, &sub
);
295 static int snd_gus_synth_delete_device(snd_seq_device_t
*dev
)
299 gus
= *(snd_gus_card_t
**)SNDRV_SEQ_DEVICE_ARGPTR(dev
);
303 if (gus
->gf1
.seq_client
>= 0) {
304 snd_seq_delete_kernel_client(gus
->gf1
.seq_client
);
305 gus
->gf1
.seq_client
= -1;
308 snd_seq_instr_list_free(&gus
->gf1
.ilist
);
312 static int __init
alsa_gus_synth_init(void)
314 static snd_seq_dev_ops_t ops
= {
315 snd_gus_synth_new_device
,
316 snd_gus_synth_delete_device
319 return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS
, &ops
,
320 sizeof(snd_gus_card_t
*));
323 static void __exit
alsa_gus_synth_exit(void)
325 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS
);
328 module_init(alsa_gus_synth_init
)
329 module_exit(alsa_gus_synth_exit
)