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);