2 * IWFFFF - AMD InterWave (tm) - 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_iw.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 IWFFFF support.");
32 MODULE_LICENSE("GPL");
34 static unsigned int snd_seq_iwffff_size(unsigned int size
, unsigned int format
)
36 unsigned int result
= size
;
38 if (format
& IWFFFF_WAVE_16BIT
)
40 if (format
& IWFFFF_WAVE_STEREO
)
45 static void snd_seq_iwffff_copy_lfo_from_stream(iwffff_lfo_t
*fp
,
48 fp
->freq
= le16_to_cpu(fx
->freq
);
49 fp
->depth
= le16_to_cpu(fx
->depth
);
50 fp
->sweep
= le16_to_cpu(fx
->sweep
);
51 fp
->shape
= fx
->shape
;
52 fp
->delay
= fx
->delay
;
55 static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype
,
61 unsigned int __nocast gfp_mask
)
64 iwffff_env_record_t
*rp
, *rp_last
;
65 iwffff_xenv_record_t rx
;
66 iwffff_env_point_t
*pp
;
67 iwffff_xenv_point_t px
;
70 ep
->flags
= ex
->flags
;
72 ep
->index
= ex
->index
;
75 if (*len
< (long)sizeof(__u32
))
77 if (copy_from_user(&stype
, *data
, sizeof(stype
)))
79 if (stype
== IWFFFF_STRU_WAVE
)
81 if (req_stype
!= stype
) {
82 if (stype
== IWFFFF_STRU_ENV_RECP
||
83 stype
== IWFFFF_STRU_ENV_RECV
)
86 if (*len
< (long)sizeof(rx
))
88 if (copy_from_user(&rx
, *data
, sizeof(rx
)))
92 points_size
= (le16_to_cpu(rx
.nattack
) + le16_to_cpu(rx
.nrelease
)) * 2 * sizeof(__u16
);
93 if (points_size
> *len
)
95 rp
= kcalloc(1, sizeof(*rp
) + points_size
, gfp_mask
);
98 rp
->nattack
= le16_to_cpu(rx
.nattack
);
99 rp
->nrelease
= le16_to_cpu(rx
.nrelease
);
100 rp
->sustain_offset
= le16_to_cpu(rx
.sustain_offset
);
101 rp
->sustain_rate
= le16_to_cpu(rx
.sustain_rate
);
102 rp
->release_rate
= le16_to_cpu(rx
.release_rate
);
103 rp
->hirange
= rx
.hirange
;
104 pp
= (iwffff_env_point_t
*)(rp
+ 1);
105 for (idx
= 0; idx
< rp
->nattack
+ rp
->nrelease
; idx
++) {
106 if (copy_from_user(&px
, *data
, sizeof(px
)))
110 pp
->offset
= le16_to_cpu(px
.offset
);
111 pp
->rate
= le16_to_cpu(px
.rate
);
113 if (ep
->record
== NULL
) {
123 static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t
*ops
,
129 iwffff_wave_t
*wp
, *prev
;
132 unsigned int gfp_mask
;
133 unsigned int real_size
;
135 gfp_mask
= atomic
? GFP_ATOMIC
: GFP_KERNEL
;
136 if (*len
< (long)sizeof(xp
))
138 if (copy_from_user(&xp
, *data
, sizeof(xp
)))
142 wp
= kcalloc(1, sizeof(*wp
), gfp_mask
);
145 wp
->share_id
[0] = le32_to_cpu(xp
.share_id
[0]);
146 wp
->share_id
[1] = le32_to_cpu(xp
.share_id
[1]);
147 wp
->share_id
[2] = le32_to_cpu(xp
.share_id
[2]);
148 wp
->share_id
[3] = le32_to_cpu(xp
.share_id
[3]);
149 wp
->format
= le32_to_cpu(xp
.format
);
150 wp
->address
.memory
= le32_to_cpu(xp
.offset
);
151 wp
->size
= le32_to_cpu(xp
.size
);
152 wp
->start
= le32_to_cpu(xp
.start
);
153 wp
->loop_start
= le32_to_cpu(xp
.loop_start
);
154 wp
->loop_end
= le32_to_cpu(xp
.loop_end
);
155 wp
->loop_repeat
= le16_to_cpu(xp
.loop_repeat
);
156 wp
->sample_ratio
= le32_to_cpu(xp
.sample_ratio
);
157 wp
->attenuation
= xp
.attenuation
;
158 wp
->low_note
= xp
.low_note
;
159 wp
->high_note
= xp
.high_note
;
160 real_size
= snd_seq_iwffff_size(wp
->size
, wp
->format
);
161 if (!(wp
->format
& IWFFFF_WAVE_ROM
)) {
162 if ((long)real_size
> *len
) {
167 if (ops
->put_sample
) {
168 err
= ops
->put_sample(ops
->private_data
, wp
,
169 *data
, real_size
, atomic
);
175 if (!(wp
->format
& IWFFFF_WAVE_ROM
)) {
181 while (prev
->next
) prev
= prev
->next
;
189 static void snd_seq_iwffff_env_free(snd_iwffff_ops_t
*ops
,
193 iwffff_env_record_t
*rec
;
195 while ((rec
= env
->record
) != NULL
) {
196 env
->record
= rec
->next
;
201 static void snd_seq_iwffff_wave_free(snd_iwffff_ops_t
*ops
,
205 if (ops
->remove_sample
)
206 ops
->remove_sample(ops
->private_data
, wave
, atomic
);
210 static void snd_seq_iwffff_instr_free(snd_iwffff_ops_t
*ops
,
211 iwffff_instrument_t
*ip
,
214 iwffff_layer_t
*layer
;
217 while ((layer
= ip
->layer
) != NULL
) {
218 ip
->layer
= layer
->next
;
219 snd_seq_iwffff_env_free(ops
, &layer
->penv
, atomic
);
220 snd_seq_iwffff_env_free(ops
, &layer
->venv
, atomic
);
221 while ((wave
= layer
->wave
) != NULL
) {
222 layer
->wave
= wave
->next
;
223 snd_seq_iwffff_wave_free(ops
, wave
, atomic
);
229 static int snd_seq_iwffff_put(void *private_data
, snd_seq_kinstr_t
*instr
,
230 char __user
*instr_data
, long len
, int atomic
,
233 snd_iwffff_ops_t
*ops
= (snd_iwffff_ops_t
*)private_data
;
234 iwffff_instrument_t
*ip
;
235 iwffff_xinstrument_t ix
;
236 iwffff_layer_t
*lp
, *prev_lp
;
239 unsigned int gfp_mask
;
241 if (cmd
!= SNDRV_SEQ_INSTR_PUT_CMD_CREATE
)
243 gfp_mask
= atomic
? GFP_ATOMIC
: GFP_KERNEL
;
244 /* copy instrument data */
245 if (len
< (long)sizeof(ix
))
247 if (copy_from_user(&ix
, instr_data
, sizeof(ix
)))
249 if (ix
.stype
!= IWFFFF_STRU_INSTR
)
251 instr_data
+= sizeof(ix
);
253 ip
= (iwffff_instrument_t
*)KINSTR_DATA(instr
);
254 ip
->exclusion
= le16_to_cpu(ix
.exclusion
);
255 ip
->layer_type
= le16_to_cpu(ix
.layer_type
);
256 ip
->exclusion_group
= le16_to_cpu(ix
.exclusion_group
);
257 ip
->effect1
= ix
.effect1
;
258 ip
->effect1_depth
= ix
.effect1_depth
;
259 ip
->effect2
= ix
.effect2
;
260 ip
->effect2_depth
= ix
.effect2_depth
;
264 if (len
< (long)sizeof(iwffff_xlayer_t
)) {
265 snd_seq_iwffff_instr_free(ops
, ip
, atomic
);
268 if (copy_from_user(&lx
, instr_data
, sizeof(lx
)))
270 instr_data
+= sizeof(lx
);
272 if (lx
.stype
!= IWFFFF_STRU_LAYER
) {
273 snd_seq_iwffff_instr_free(ops
, ip
, atomic
);
276 lp
= kcalloc(1, sizeof(*lp
), gfp_mask
);
278 snd_seq_iwffff_instr_free(ops
, ip
, atomic
);
287 lp
->flags
= lx
.flags
;
288 lp
->velocity_mode
= lx
.velocity_mode
;
289 lp
->layer_event
= lx
.layer_event
;
290 lp
->low_range
= lx
.low_range
;
291 lp
->high_range
= lx
.high_range
;
293 lp
->pan_freq_scale
= lx
.pan_freq_scale
;
294 lp
->attenuation
= lx
.attenuation
;
295 snd_seq_iwffff_copy_lfo_from_stream(&lp
->tremolo
, &lx
.tremolo
);
296 snd_seq_iwffff_copy_lfo_from_stream(&lp
->vibrato
, &lx
.vibrato
);
297 lp
->freq_scale
= le16_to_cpu(lx
.freq_scale
);
298 lp
->freq_center
= lx
.freq_center
;
299 err
= snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP
,
305 snd_seq_iwffff_instr_free(ops
, ip
, atomic
);
308 err
= snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV
,
314 snd_seq_iwffff_instr_free(ops
, ip
, atomic
);
317 while (len
> (long)sizeof(__u32
)) {
320 if (copy_from_user(&stype
, instr_data
, sizeof(stype
)))
322 if (stype
!= IWFFFF_STRU_WAVE
)
324 err
= snd_seq_iwffff_copy_wave_from_stream(ops
,
330 snd_seq_iwffff_instr_free(ops
, ip
, atomic
);
338 static void snd_seq_iwffff_copy_lfo_to_stream(iwffff_xlfo_t
*fx
,
341 fx
->freq
= cpu_to_le16(fp
->freq
);
342 fx
->depth
= cpu_to_le16(fp
->depth
);
343 fx
->sweep
= cpu_to_le16(fp
->sweep
);
344 fp
->shape
= fx
->shape
;
345 fp
->delay
= fx
->delay
;
348 static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype
,
355 iwffff_env_record_t
*rp
;
356 iwffff_xenv_record_t rx
;
357 iwffff_env_point_t
*pp
;
358 iwffff_xenv_point_t px
;
359 int points_size
, idx
;
361 ex
->flags
= ep
->flags
;
363 ex
->index
= ep
->index
;
364 for (rp
= ep
->record
; rp
; rp
= rp
->next
) {
365 if (*len
< (long)sizeof(rx
))
367 memset(&rx
, 0, sizeof(rx
));
368 rx
.stype
= req_stype
;
369 rx
.nattack
= cpu_to_le16(rp
->nattack
);
370 rx
.nrelease
= cpu_to_le16(rp
->nrelease
);
371 rx
.sustain_offset
= cpu_to_le16(rp
->sustain_offset
);
372 rx
.sustain_rate
= cpu_to_le16(rp
->sustain_rate
);
373 rx
.release_rate
= cpu_to_le16(rp
->release_rate
);
374 rx
.hirange
= cpu_to_le16(rp
->hirange
);
375 if (copy_to_user(*data
, &rx
, sizeof(rx
)))
379 points_size
= (rp
->nattack
+ rp
->nrelease
) * 2 * sizeof(__u16
);
380 if (*len
< points_size
)
382 pp
= (iwffff_env_point_t
*)(rp
+ 1);
383 for (idx
= 0; idx
< rp
->nattack
+ rp
->nrelease
; idx
++) {
384 px
.offset
= cpu_to_le16(pp
->offset
);
385 px
.rate
= cpu_to_le16(pp
->rate
);
386 if (copy_to_user(*data
, &px
, sizeof(px
)))
395 static int snd_seq_iwffff_copy_wave_to_stream(snd_iwffff_ops_t
*ops
,
404 unsigned int real_size
;
406 for (wp
= lp
->wave
; wp
; wp
= wp
->next
) {
407 if (*len
< (long)sizeof(xp
))
409 memset(&xp
, 0, sizeof(xp
));
410 xp
.stype
= IWFFFF_STRU_WAVE
;
411 xp
.share_id
[0] = cpu_to_le32(wp
->share_id
[0]);
412 xp
.share_id
[1] = cpu_to_le32(wp
->share_id
[1]);
413 xp
.share_id
[2] = cpu_to_le32(wp
->share_id
[2]);
414 xp
.share_id
[3] = cpu_to_le32(wp
->share_id
[3]);
415 xp
.format
= cpu_to_le32(wp
->format
);
416 if (wp
->format
& IWFFFF_WAVE_ROM
)
417 xp
.offset
= cpu_to_le32(wp
->address
.memory
);
418 xp
.size
= cpu_to_le32(wp
->size
);
419 xp
.start
= cpu_to_le32(wp
->start
);
420 xp
.loop_start
= cpu_to_le32(wp
->loop_start
);
421 xp
.loop_end
= cpu_to_le32(wp
->loop_end
);
422 xp
.loop_repeat
= cpu_to_le32(wp
->loop_repeat
);
423 xp
.sample_ratio
= cpu_to_le32(wp
->sample_ratio
);
424 xp
.attenuation
= wp
->attenuation
;
425 xp
.low_note
= wp
->low_note
;
426 xp
.high_note
= wp
->high_note
;
427 if (copy_to_user(*data
, &xp
, sizeof(xp
)))
431 real_size
= snd_seq_iwffff_size(wp
->size
, wp
->format
);
432 if (!(wp
->format
& IWFFFF_WAVE_ROM
)) {
433 if (*len
< (long)real_size
)
436 if (ops
->get_sample
) {
437 err
= ops
->get_sample(ops
->private_data
, wp
,
438 *data
, real_size
, atomic
);
442 if (!(wp
->format
& IWFFFF_WAVE_ROM
)) {
450 static int snd_seq_iwffff_get(void *private_data
, snd_seq_kinstr_t
*instr
,
451 char __user
*instr_data
, long len
, int atomic
, int cmd
)
453 snd_iwffff_ops_t
*ops
= (snd_iwffff_ops_t
*)private_data
;
454 iwffff_instrument_t
*ip
;
455 iwffff_xinstrument_t ix
;
458 char __user
*layer_instr_data
;
461 if (cmd
!= SNDRV_SEQ_INSTR_GET_CMD_FULL
)
463 if (len
< (long)sizeof(ix
))
465 memset(&ix
, 0, sizeof(ix
));
466 ip
= (iwffff_instrument_t
*)KINSTR_DATA(instr
);
467 ix
.stype
= IWFFFF_STRU_INSTR
;
468 ix
.exclusion
= cpu_to_le16(ip
->exclusion
);
469 ix
.layer_type
= cpu_to_le16(ip
->layer_type
);
470 ix
.exclusion_group
= cpu_to_le16(ip
->exclusion_group
);
471 ix
.effect1
= cpu_to_le16(ip
->effect1
);
472 ix
.effect1_depth
= cpu_to_le16(ip
->effect1_depth
);
473 ix
.effect2
= ip
->effect2
;
474 ix
.effect2_depth
= ip
->effect2_depth
;
475 if (copy_to_user(instr_data
, &ix
, sizeof(ix
)))
477 instr_data
+= sizeof(ix
);
479 for (lp
= ip
->layer
; lp
; lp
= lp
->next
) {
480 if (len
< (long)sizeof(lx
))
482 memset(&lx
, 0, sizeof(lx
));
483 lx
.stype
= IWFFFF_STRU_LAYER
;
484 lx
.flags
= lp
->flags
;
485 lx
.velocity_mode
= lp
->velocity_mode
;
486 lx
.layer_event
= lp
->layer_event
;
487 lx
.low_range
= lp
->low_range
;
488 lx
.high_range
= lp
->high_range
;
490 lx
.pan_freq_scale
= lp
->pan_freq_scale
;
491 lx
.attenuation
= lp
->attenuation
;
492 snd_seq_iwffff_copy_lfo_to_stream(&lx
.tremolo
, &lp
->tremolo
);
493 snd_seq_iwffff_copy_lfo_to_stream(&lx
.vibrato
, &lp
->vibrato
);
494 layer_instr_data
= instr_data
;
495 instr_data
+= sizeof(lx
);
497 err
= snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP
,
503 err
= snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV
,
509 /* layer structure updating is now finished */
510 if (copy_to_user(layer_instr_data
, &lx
, sizeof(lx
)))
512 err
= snd_seq_iwffff_copy_wave_to_stream(ops
,
523 static long snd_seq_iwffff_env_size_in_stream(iwffff_env_t
*ep
)
526 iwffff_env_record_t
*rp
;
528 for (rp
= ep
->record
; rp
; rp
= rp
->next
) {
529 result
+= sizeof(iwffff_xenv_record_t
);
530 result
+= (rp
->nattack
+ rp
->nrelease
) * 2 * sizeof(__u16
);
535 static long snd_seq_iwffff_wave_size_in_stream(iwffff_layer_t
*lp
)
540 for (wp
= lp
->wave
; wp
; wp
= wp
->next
) {
541 result
+= sizeof(iwffff_xwave_t
);
542 if (!(wp
->format
& IWFFFF_WAVE_ROM
))
548 static int snd_seq_iwffff_get_size(void *private_data
, snd_seq_kinstr_t
*instr
,
552 iwffff_instrument_t
*ip
;
556 ip
= (iwffff_instrument_t
*)KINSTR_DATA(instr
);
557 result
= sizeof(iwffff_xinstrument_t
);
558 for (lp
= ip
->layer
; lp
; lp
= lp
->next
) {
559 result
+= sizeof(iwffff_xlayer_t
);
560 result
+= snd_seq_iwffff_env_size_in_stream(&lp
->penv
);
561 result
+= snd_seq_iwffff_env_size_in_stream(&lp
->venv
);
562 result
+= snd_seq_iwffff_wave_size_in_stream(lp
);
568 static int snd_seq_iwffff_remove(void *private_data
,
569 snd_seq_kinstr_t
*instr
,
572 snd_iwffff_ops_t
*ops
= (snd_iwffff_ops_t
*)private_data
;
573 iwffff_instrument_t
*ip
;
575 ip
= (iwffff_instrument_t
*)KINSTR_DATA(instr
);
576 snd_seq_iwffff_instr_free(ops
, ip
, atomic
);
580 static void snd_seq_iwffff_notify(void *private_data
,
581 snd_seq_kinstr_t
*instr
,
584 snd_iwffff_ops_t
*ops
= (snd_iwffff_ops_t
*)private_data
;
587 ops
->notify(ops
->private_data
, instr
, what
);
590 int snd_seq_iwffff_init(snd_iwffff_ops_t
*ops
,
592 snd_seq_kinstr_ops_t
*next
)
594 memset(ops
, 0, sizeof(*ops
));
595 ops
->private_data
= private_data
;
596 ops
->kops
.private_data
= ops
;
597 ops
->kops
.add_len
= sizeof(iwffff_instrument_t
);
598 ops
->kops
.instr_type
= SNDRV_SEQ_INSTR_ID_INTERWAVE
;
599 ops
->kops
.put
= snd_seq_iwffff_put
;
600 ops
->kops
.get
= snd_seq_iwffff_get
;
601 ops
->kops
.get_size
= snd_seq_iwffff_get_size
;
602 ops
->kops
.remove
= snd_seq_iwffff_remove
;
603 ops
->kops
.notify
= snd_seq_iwffff_notify
;
604 ops
->kops
.next
= next
;
612 static int __init
alsa_ainstr_iw_init(void)
617 static void __exit
alsa_ainstr_iw_exit(void)
621 module_init(alsa_ainstr_iw_init
)
622 module_exit(alsa_ainstr_iw_exit
)
624 EXPORT_SYMBOL(snd_seq_iwffff_init
);