2 * GF1 (GUS) Patch - Instrument routines
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
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.
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.
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
21 #include <sound/driver.h>
22 #include <linux/init.h>
23 #include <linux/sched.h>
24 #include <linux/slab.h>
25 #include <sound/core.h>
26 #include <sound/ainstr_gf1.h>
27 #include <sound/initval.h>
28 #include <asm/uaccess.h>
30 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
31 MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support.");
32 MODULE_LICENSE("GPL");
34 static unsigned int snd_seq_gf1_size(unsigned int size
, unsigned int format
)
36 unsigned int result
= size
;
38 if (format
& GF1_WAVE_16BIT
)
40 if (format
& GF1_WAVE_STEREO
)
45 static int snd_seq_gf1_copy_wave_from_stream(snd_gf1_ops_t
*ops
,
51 gf1_wave_t
*wp
, *prev
;
54 unsigned int real_size
;
56 gfp_mask
= atomic
? GFP_ATOMIC
: GFP_KERNEL
;
57 if (*len
< (long)sizeof(xp
))
59 if (copy_from_user(&xp
, *data
, sizeof(xp
)))
63 wp
= kcalloc(1, sizeof(*wp
), gfp_mask
);
66 wp
->share_id
[0] = le32_to_cpu(xp
.share_id
[0]);
67 wp
->share_id
[1] = le32_to_cpu(xp
.share_id
[1]);
68 wp
->share_id
[2] = le32_to_cpu(xp
.share_id
[2]);
69 wp
->share_id
[3] = le32_to_cpu(xp
.share_id
[3]);
70 wp
->format
= le32_to_cpu(xp
.format
);
71 wp
->size
= le32_to_cpu(xp
.size
);
72 wp
->start
= le32_to_cpu(xp
.start
);
73 wp
->loop_start
= le32_to_cpu(xp
.loop_start
);
74 wp
->loop_end
= le32_to_cpu(xp
.loop_end
);
75 wp
->loop_repeat
= le16_to_cpu(xp
.loop_repeat
);
77 wp
->sample_rate
= le32_to_cpu(xp
.sample_rate
);
78 wp
->low_frequency
= le32_to_cpu(xp
.low_frequency
);
79 wp
->high_frequency
= le32_to_cpu(xp
.high_frequency
);
80 wp
->root_frequency
= le32_to_cpu(xp
.root_frequency
);
81 wp
->tune
= le16_to_cpu(xp
.tune
);
82 wp
->balance
= xp
.balance
;
83 memcpy(wp
->envelope_rate
, xp
.envelope_rate
, 6);
84 memcpy(wp
->envelope_offset
, xp
.envelope_offset
, 6);
85 wp
->tremolo_sweep
= xp
.tremolo_sweep
;
86 wp
->tremolo_rate
= xp
.tremolo_rate
;
87 wp
->tremolo_depth
= xp
.tremolo_depth
;
88 wp
->vibrato_sweep
= xp
.vibrato_sweep
;
89 wp
->vibrato_rate
= xp
.vibrato_rate
;
90 wp
->vibrato_depth
= xp
.vibrato_depth
;
91 wp
->scale_frequency
= le16_to_cpu(xp
.scale_frequency
);
92 wp
->scale_factor
= le16_to_cpu(xp
.scale_factor
);
93 real_size
= snd_seq_gf1_size(wp
->size
, wp
->format
);
94 if ((long)real_size
> *len
) {
98 if (ops
->put_sample
) {
99 err
= ops
->put_sample(ops
->private_data
, wp
,
100 *data
, real_size
, atomic
);
110 while (prev
->next
) prev
= prev
->next
;
118 static void snd_seq_gf1_wave_free(snd_gf1_ops_t
*ops
,
122 if (ops
->remove_sample
)
123 ops
->remove_sample(ops
->private_data
, wave
, atomic
);
127 static void snd_seq_gf1_instr_free(snd_gf1_ops_t
*ops
,
128 gf1_instrument_t
*ip
,
133 while ((wave
= ip
->wave
) != NULL
) {
134 ip
->wave
= wave
->next
;
135 snd_seq_gf1_wave_free(ops
, wave
, atomic
);
139 static int snd_seq_gf1_put(void *private_data
, snd_seq_kinstr_t
*instr
,
140 char __user
*instr_data
, long len
, int atomic
,
143 snd_gf1_ops_t
*ops
= (snd_gf1_ops_t
*)private_data
;
144 gf1_instrument_t
*ip
;
145 gf1_xinstrument_t ix
;
148 if (cmd
!= SNDRV_SEQ_INSTR_PUT_CMD_CREATE
)
150 gfp_mask
= atomic
? GFP_ATOMIC
: GFP_KERNEL
;
151 /* copy instrument data */
152 if (len
< (long)sizeof(ix
))
154 if (copy_from_user(&ix
, instr_data
, sizeof(ix
)))
156 if (ix
.stype
!= GF1_STRU_INSTR
)
158 instr_data
+= sizeof(ix
);
160 ip
= (gf1_instrument_t
*)KINSTR_DATA(instr
);
161 ip
->exclusion
= le16_to_cpu(ix
.exclusion
);
162 ip
->exclusion_group
= le16_to_cpu(ix
.exclusion_group
);
163 ip
->effect1
= ix
.effect1
;
164 ip
->effect1_depth
= ix
.effect1_depth
;
165 ip
->effect2
= ix
.effect2
;
166 ip
->effect2_depth
= ix
.effect2_depth
;
168 while (len
> (long)sizeof(__u32
)) {
171 if (copy_from_user(&stype
, instr_data
, sizeof(stype
)))
173 if (stype
!= GF1_STRU_WAVE
) {
174 snd_seq_gf1_instr_free(ops
, ip
, atomic
);
177 err
= snd_seq_gf1_copy_wave_from_stream(ops
,
183 snd_seq_gf1_instr_free(ops
, ip
, atomic
);
190 static int snd_seq_gf1_copy_wave_to_stream(snd_gf1_ops_t
*ops
,
191 gf1_instrument_t
*ip
,
199 unsigned int real_size
;
201 for (wp
= ip
->wave
; wp
; wp
= wp
->next
) {
202 if (*len
< (long)sizeof(xp
))
204 memset(&xp
, 0, sizeof(xp
));
205 xp
.stype
= GF1_STRU_WAVE
;
206 xp
.share_id
[0] = cpu_to_le32(wp
->share_id
[0]);
207 xp
.share_id
[1] = cpu_to_le32(wp
->share_id
[1]);
208 xp
.share_id
[2] = cpu_to_le32(wp
->share_id
[2]);
209 xp
.share_id
[3] = cpu_to_le32(wp
->share_id
[3]);
210 xp
.format
= cpu_to_le32(wp
->format
);
211 xp
.size
= cpu_to_le32(wp
->size
);
212 xp
.start
= cpu_to_le32(wp
->start
);
213 xp
.loop_start
= cpu_to_le32(wp
->loop_start
);
214 xp
.loop_end
= cpu_to_le32(wp
->loop_end
);
215 xp
.loop_repeat
= cpu_to_le32(wp
->loop_repeat
);
216 xp
.flags
= wp
->flags
;
217 xp
.sample_rate
= cpu_to_le32(wp
->sample_rate
);
218 xp
.low_frequency
= cpu_to_le32(wp
->low_frequency
);
219 xp
.high_frequency
= cpu_to_le32(wp
->high_frequency
);
220 xp
.root_frequency
= cpu_to_le32(wp
->root_frequency
);
221 xp
.tune
= cpu_to_le16(wp
->tune
);
222 xp
.balance
= wp
->balance
;
223 memcpy(xp
.envelope_rate
, wp
->envelope_rate
, 6);
224 memcpy(xp
.envelope_offset
, wp
->envelope_offset
, 6);
225 xp
.tremolo_sweep
= wp
->tremolo_sweep
;
226 xp
.tremolo_rate
= wp
->tremolo_rate
;
227 xp
.tremolo_depth
= wp
->tremolo_depth
;
228 xp
.vibrato_sweep
= wp
->vibrato_sweep
;
229 xp
.vibrato_rate
= wp
->vibrato_rate
;
230 xp
.vibrato_depth
= wp
->vibrato_depth
;
231 xp
.scale_frequency
= cpu_to_le16(wp
->scale_frequency
);
232 xp
.scale_factor
= cpu_to_le16(wp
->scale_factor
);
233 if (copy_to_user(*data
, &xp
, sizeof(xp
)))
237 real_size
= snd_seq_gf1_size(wp
->size
, wp
->format
);
238 if (*len
< (long)real_size
)
240 if (ops
->get_sample
) {
241 err
= ops
->get_sample(ops
->private_data
, wp
,
242 *data
, real_size
, atomic
);
252 static int snd_seq_gf1_get(void *private_data
, snd_seq_kinstr_t
*instr
,
253 char __user
*instr_data
, long len
, int atomic
,
256 snd_gf1_ops_t
*ops
= (snd_gf1_ops_t
*)private_data
;
257 gf1_instrument_t
*ip
;
258 gf1_xinstrument_t ix
;
260 if (cmd
!= SNDRV_SEQ_INSTR_GET_CMD_FULL
)
262 if (len
< (long)sizeof(ix
))
264 memset(&ix
, 0, sizeof(ix
));
265 ip
= (gf1_instrument_t
*)KINSTR_DATA(instr
);
266 ix
.stype
= GF1_STRU_INSTR
;
267 ix
.exclusion
= cpu_to_le16(ip
->exclusion
);
268 ix
.exclusion_group
= cpu_to_le16(ip
->exclusion_group
);
269 ix
.effect1
= cpu_to_le16(ip
->effect1
);
270 ix
.effect1_depth
= cpu_to_le16(ip
->effect1_depth
);
271 ix
.effect2
= ip
->effect2
;
272 ix
.effect2_depth
= ip
->effect2_depth
;
273 if (copy_to_user(instr_data
, &ix
, sizeof(ix
)))
275 instr_data
+= sizeof(ix
);
277 return snd_seq_gf1_copy_wave_to_stream(ops
,
284 static int snd_seq_gf1_get_size(void *private_data
, snd_seq_kinstr_t
*instr
,
288 gf1_instrument_t
*ip
;
292 ip
= (gf1_instrument_t
*)KINSTR_DATA(instr
);
293 result
= sizeof(gf1_xinstrument_t
);
294 for (wp
= ip
->wave
; wp
; wp
= wp
->next
) {
295 result
+= sizeof(gf1_xwave_t
);
302 static int snd_seq_gf1_remove(void *private_data
,
303 snd_seq_kinstr_t
*instr
,
306 snd_gf1_ops_t
*ops
= (snd_gf1_ops_t
*)private_data
;
307 gf1_instrument_t
*ip
;
309 ip
= (gf1_instrument_t
*)KINSTR_DATA(instr
);
310 snd_seq_gf1_instr_free(ops
, ip
, atomic
);
314 static void snd_seq_gf1_notify(void *private_data
,
315 snd_seq_kinstr_t
*instr
,
318 snd_gf1_ops_t
*ops
= (snd_gf1_ops_t
*)private_data
;
321 ops
->notify(ops
->private_data
, instr
, what
);
324 int snd_seq_gf1_init(snd_gf1_ops_t
*ops
,
326 snd_seq_kinstr_ops_t
*next
)
328 memset(ops
, 0, sizeof(*ops
));
329 ops
->private_data
= private_data
;
330 ops
->kops
.private_data
= ops
;
331 ops
->kops
.add_len
= sizeof(gf1_instrument_t
);
332 ops
->kops
.instr_type
= SNDRV_SEQ_INSTR_ID_GUS_PATCH
;
333 ops
->kops
.put
= snd_seq_gf1_put
;
334 ops
->kops
.get
= snd_seq_gf1_get
;
335 ops
->kops
.get_size
= snd_seq_gf1_get_size
;
336 ops
->kops
.remove
= snd_seq_gf1_remove
;
337 ops
->kops
.notify
= snd_seq_gf1_notify
;
338 ops
->kops
.next
= next
;
346 static int __init
alsa_ainstr_gf1_init(void)
351 static void __exit
alsa_ainstr_gf1_exit(void)
355 module_init(alsa_ainstr_gf1_init
)
356 module_exit(alsa_ainstr_gf1_exit
)
358 EXPORT_SYMBOL(snd_seq_gf1_init
);