[PATCH] dvb: saa7134-dvb must select tda1004x
[linux-ginger.git] / sound / core / seq / instr / ainstr_iw.c
blob2622b8679ca76be886524be263517560e8f2e43b
1 /*
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)
39 result <<= 1;
40 if (format & IWFFFF_WAVE_STEREO)
41 result <<= 1;
42 return result;
45 static void snd_seq_iwffff_copy_lfo_from_stream(iwffff_lfo_t *fp,
46 iwffff_xlfo_t *fx)
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,
56 iwffff_layer_t *lp,
57 iwffff_env_t *ep,
58 iwffff_xenv_t *ex,
59 char __user **data,
60 long *len,
61 unsigned int __nocast gfp_mask)
63 __u32 stype;
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;
68 int points_size, idx;
70 ep->flags = ex->flags;
71 ep->mode = ex->mode;
72 ep->index = ex->index;
73 rp_last = NULL;
74 while (1) {
75 if (*len < (long)sizeof(__u32))
76 return -EINVAL;
77 if (copy_from_user(&stype, *data, sizeof(stype)))
78 return -EFAULT;
79 if (stype == IWFFFF_STRU_WAVE)
80 return 0;
81 if (req_stype != stype) {
82 if (stype == IWFFFF_STRU_ENV_RECP ||
83 stype == IWFFFF_STRU_ENV_RECV)
84 return 0;
86 if (*len < (long)sizeof(rx))
87 return -EINVAL;
88 if (copy_from_user(&rx, *data, sizeof(rx)))
89 return -EFAULT;
90 *data += sizeof(rx);
91 *len -= sizeof(rx);
92 points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16);
93 if (points_size > *len)
94 return -EINVAL;
95 rp = kcalloc(1, sizeof(*rp) + points_size, gfp_mask);
96 if (rp == NULL)
97 return -ENOMEM;
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)))
107 return -EFAULT;
108 *data += sizeof(px);
109 *len -= sizeof(px);
110 pp->offset = le16_to_cpu(px.offset);
111 pp->rate = le16_to_cpu(px.rate);
113 if (ep->record == NULL) {
114 ep->record = rp;
115 } else {
116 rp_last = rp;
118 rp_last = rp;
120 return 0;
123 static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t *ops,
124 iwffff_layer_t *lp,
125 char __user **data,
126 long *len,
127 int atomic)
129 iwffff_wave_t *wp, *prev;
130 iwffff_xwave_t xp;
131 int err;
132 unsigned int gfp_mask;
133 unsigned int real_size;
135 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
136 if (*len < (long)sizeof(xp))
137 return -EINVAL;
138 if (copy_from_user(&xp, *data, sizeof(xp)))
139 return -EFAULT;
140 *data += sizeof(xp);
141 *len -= sizeof(xp);
142 wp = kcalloc(1, sizeof(*wp), gfp_mask);
143 if (wp == NULL)
144 return -ENOMEM;
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) {
163 kfree(wp);
164 return -ENOMEM;
167 if (ops->put_sample) {
168 err = ops->put_sample(ops->private_data, wp,
169 *data, real_size, atomic);
170 if (err < 0) {
171 kfree(wp);
172 return err;
175 if (!(wp->format & IWFFFF_WAVE_ROM)) {
176 *data += real_size;
177 *len -= real_size;
179 prev = lp->wave;
180 if (prev) {
181 while (prev->next) prev = prev->next;
182 prev->next = wp;
183 } else {
184 lp->wave = wp;
186 return 0;
189 static void snd_seq_iwffff_env_free(snd_iwffff_ops_t *ops,
190 iwffff_env_t *env,
191 int atomic)
193 iwffff_env_record_t *rec;
195 while ((rec = env->record) != NULL) {
196 env->record = rec->next;
197 kfree(rec);
201 static void snd_seq_iwffff_wave_free(snd_iwffff_ops_t *ops,
202 iwffff_wave_t *wave,
203 int atomic)
205 if (ops->remove_sample)
206 ops->remove_sample(ops->private_data, wave, atomic);
207 kfree(wave);
210 static void snd_seq_iwffff_instr_free(snd_iwffff_ops_t *ops,
211 iwffff_instrument_t *ip,
212 int atomic)
214 iwffff_layer_t *layer;
215 iwffff_wave_t *wave;
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);
225 kfree(layer);
229 static int snd_seq_iwffff_put(void *private_data, snd_seq_kinstr_t *instr,
230 char __user *instr_data, long len, int atomic,
231 int cmd)
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;
237 iwffff_xlayer_t lx;
238 int err;
239 unsigned int gfp_mask;
241 if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
242 return -EINVAL;
243 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
244 /* copy instrument data */
245 if (len < (long)sizeof(ix))
246 return -EINVAL;
247 if (copy_from_user(&ix, instr_data, sizeof(ix)))
248 return -EFAULT;
249 if (ix.stype != IWFFFF_STRU_INSTR)
250 return -EINVAL;
251 instr_data += sizeof(ix);
252 len -= 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;
261 /* copy layers */
262 prev_lp = NULL;
263 while (len > 0) {
264 if (len < (long)sizeof(iwffff_xlayer_t)) {
265 snd_seq_iwffff_instr_free(ops, ip, atomic);
266 return -EINVAL;
268 if (copy_from_user(&lx, instr_data, sizeof(lx)))
269 return -EFAULT;
270 instr_data += sizeof(lx);
271 len -= sizeof(lx);
272 if (lx.stype != IWFFFF_STRU_LAYER) {
273 snd_seq_iwffff_instr_free(ops, ip, atomic);
274 return -EINVAL;
276 lp = kcalloc(1, sizeof(*lp), gfp_mask);
277 if (lp == NULL) {
278 snd_seq_iwffff_instr_free(ops, ip, atomic);
279 return -ENOMEM;
281 if (prev_lp) {
282 prev_lp->next = lp;
283 } else {
284 ip->layer = lp;
286 prev_lp = lp;
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;
292 lp->pan = lx.pan;
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,
301 &lp->penv, &lx.penv,
302 &instr_data, &len,
303 gfp_mask);
304 if (err < 0) {
305 snd_seq_iwffff_instr_free(ops, ip, atomic);
306 return err;
308 err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV,
310 &lp->venv, &lx.venv,
311 &instr_data, &len,
312 gfp_mask);
313 if (err < 0) {
314 snd_seq_iwffff_instr_free(ops, ip, atomic);
315 return err;
317 while (len > (long)sizeof(__u32)) {
318 __u32 stype;
320 if (copy_from_user(&stype, instr_data, sizeof(stype)))
321 return -EFAULT;
322 if (stype != IWFFFF_STRU_WAVE)
323 break;
324 err = snd_seq_iwffff_copy_wave_from_stream(ops,
326 &instr_data,
327 &len,
328 atomic);
329 if (err < 0) {
330 snd_seq_iwffff_instr_free(ops, ip, atomic);
331 return err;
335 return 0;
338 static void snd_seq_iwffff_copy_lfo_to_stream(iwffff_xlfo_t *fx,
339 iwffff_lfo_t *fp)
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,
349 iwffff_layer_t *lp,
350 iwffff_xenv_t *ex,
351 iwffff_env_t *ep,
352 char __user **data,
353 long *len)
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;
362 ex->mode = ep->mode;
363 ex->index = ep->index;
364 for (rp = ep->record; rp; rp = rp->next) {
365 if (*len < (long)sizeof(rx))
366 return -ENOMEM;
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)))
376 return -EFAULT;
377 *data += sizeof(rx);
378 *len -= sizeof(rx);
379 points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
380 if (*len < points_size)
381 return -ENOMEM;
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)))
387 return -EFAULT;
388 *data += sizeof(px);
389 *len -= sizeof(px);
392 return 0;
395 static int snd_seq_iwffff_copy_wave_to_stream(snd_iwffff_ops_t *ops,
396 iwffff_layer_t *lp,
397 char __user **data,
398 long *len,
399 int atomic)
401 iwffff_wave_t *wp;
402 iwffff_xwave_t xp;
403 int err;
404 unsigned int real_size;
406 for (wp = lp->wave; wp; wp = wp->next) {
407 if (*len < (long)sizeof(xp))
408 return -ENOMEM;
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)))
428 return -EFAULT;
429 *data += sizeof(xp);
430 *len -= 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)
434 return -ENOMEM;
436 if (ops->get_sample) {
437 err = ops->get_sample(ops->private_data, wp,
438 *data, real_size, atomic);
439 if (err < 0)
440 return err;
442 if (!(wp->format & IWFFFF_WAVE_ROM)) {
443 *data += real_size;
444 *len -= real_size;
447 return 0;
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;
456 iwffff_layer_t *lp;
457 iwffff_xlayer_t lx;
458 char __user *layer_instr_data;
459 int err;
461 if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
462 return -EINVAL;
463 if (len < (long)sizeof(ix))
464 return -ENOMEM;
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)))
476 return -EFAULT;
477 instr_data += sizeof(ix);
478 len -= sizeof(ix);
479 for (lp = ip->layer; lp; lp = lp->next) {
480 if (len < (long)sizeof(lx))
481 return -ENOMEM;
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;
489 lx.pan = lp->pan;
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);
496 len -= sizeof(lx);
497 err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP,
499 &lx.penv, &lp->penv,
500 &instr_data, &len);
501 if (err < 0)
502 return err;
503 err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV,
505 &lx.venv, &lp->venv,
506 &instr_data, &len);
507 if (err < 0)
508 return err;
509 /* layer structure updating is now finished */
510 if (copy_to_user(layer_instr_data, &lx, sizeof(lx)))
511 return -EFAULT;
512 err = snd_seq_iwffff_copy_wave_to_stream(ops,
514 &instr_data,
515 &len,
516 atomic);
517 if (err < 0)
518 return err;
520 return 0;
523 static long snd_seq_iwffff_env_size_in_stream(iwffff_env_t *ep)
525 long result = 0;
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);
532 return 0;
535 static long snd_seq_iwffff_wave_size_in_stream(iwffff_layer_t *lp)
537 long result = 0;
538 iwffff_wave_t *wp;
540 for (wp = lp->wave; wp; wp = wp->next) {
541 result += sizeof(iwffff_xwave_t);
542 if (!(wp->format & IWFFFF_WAVE_ROM))
543 result += wp->size;
545 return result;
548 static int snd_seq_iwffff_get_size(void *private_data, snd_seq_kinstr_t *instr,
549 long *size)
551 long result;
552 iwffff_instrument_t *ip;
553 iwffff_layer_t *lp;
555 *size = 0;
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);
564 *size = result;
565 return 0;
568 static int snd_seq_iwffff_remove(void *private_data,
569 snd_seq_kinstr_t *instr,
570 int atomic)
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);
577 return 0;
580 static void snd_seq_iwffff_notify(void *private_data,
581 snd_seq_kinstr_t *instr,
582 int what)
584 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
586 if (ops->notify)
587 ops->notify(ops->private_data, instr, what);
590 int snd_seq_iwffff_init(snd_iwffff_ops_t *ops,
591 void *private_data,
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;
605 return 0;
609 * Init part
612 static int __init alsa_ainstr_iw_init(void)
614 return 0;
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);