1/*
2 *   IWFFFF - AMD InterWave (tm) - Instrument routines
3 *   Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 *
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.
9 *
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.
14 *
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
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <sound/core.h>
25#include <sound/ainstr_iw.h>
26#include <sound/initval.h>
27#include <asm/uaccess.h>
28
29MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
30MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support.");
31MODULE_LICENSE("GPL");
32
33static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format)
34{
35	unsigned int result = size;
36
37	if (format & IWFFFF_WAVE_16BIT)
38		result <<= 1;
39	if (format & IWFFFF_WAVE_STEREO)
40		result <<= 1;
41	return result;
42}
43
44static void snd_seq_iwffff_copy_lfo_from_stream(struct iwffff_lfo *fp,
45						struct iwffff_xlfo *fx)
46{
47	fp->freq = le16_to_cpu(fx->freq);
48	fp->depth = le16_to_cpu(fx->depth);
49	fp->sweep = le16_to_cpu(fx->sweep);
50	fp->shape = fx->shape;
51	fp->delay = fx->delay;
52}
53
54static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype,
55					       struct iwffff_layer *lp,
56					       struct iwffff_env *ep,
57					       struct iwffff_xenv *ex,
58					       char __user **data,
59					       long *len,
60					       gfp_t gfp_mask)
61{
62	__u32 stype;
63	struct iwffff_env_record *rp, *rp_last;
64	struct iwffff_xenv_record rx;
65	struct iwffff_env_point *pp;
66	struct iwffff_xenv_point px;
67	int points_size, idx;
68
69	ep->flags = ex->flags;
70	ep->mode = ex->mode;
71	ep->index = ex->index;
72	rp_last = NULL;
73	while (1) {
74		if (*len < (long)sizeof(__u32))
75			return -EINVAL;
76		if (copy_from_user(&stype, *data, sizeof(stype)))
77			return -EFAULT;
78		if (stype == IWFFFF_STRU_WAVE)
79			return 0;
80		if (req_stype != stype) {
81			if (stype == IWFFFF_STRU_ENV_RECP ||
82			    stype == IWFFFF_STRU_ENV_RECV)
83				return 0;
84		}
85		if (*len < (long)sizeof(rx))
86			return -EINVAL;
87		if (copy_from_user(&rx, *data, sizeof(rx)))
88			return -EFAULT;
89		*data += sizeof(rx);
90		*len -= sizeof(rx);
91		points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16);
92		if (points_size > *len)
93			return -EINVAL;
94		rp = kzalloc(sizeof(*rp) + points_size, gfp_mask);
95		if (rp == NULL)
96			return -ENOMEM;
97		rp->nattack = le16_to_cpu(rx.nattack);
98		rp->nrelease = le16_to_cpu(rx.nrelease);
99		rp->sustain_offset = le16_to_cpu(rx.sustain_offset);
100		rp->sustain_rate = le16_to_cpu(rx.sustain_rate);
101		rp->release_rate = le16_to_cpu(rx.release_rate);
102		rp->hirange = rx.hirange;
103		pp = (struct iwffff_env_point *)(rp + 1);
104		for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
105			if (copy_from_user(&px, *data, sizeof(px)))
106				return -EFAULT;
107			*data += sizeof(px);
108			*len -= sizeof(px);
109			pp->offset = le16_to_cpu(px.offset);
110			pp->rate = le16_to_cpu(px.rate);
111		}
112		if (ep->record == NULL) {
113			ep->record = rp;
114		} else {
115			rp_last = rp;
116		}
117		rp_last = rp;
118	}
119	return 0;
120}
121
122static int snd_seq_iwffff_copy_wave_from_stream(struct snd_iwffff_ops *ops,
123						struct iwffff_layer *lp,
124					        char __user **data,
125					        long *len,
126					        int atomic)
127{
128	struct iwffff_wave *wp, *prev;
129	struct iwffff_xwave xp;
130	int err;
131	gfp_t gfp_mask;
132	unsigned int real_size;
133
134	gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
135	if (*len < (long)sizeof(xp))
136		return -EINVAL;
137	if (copy_from_user(&xp, *data, sizeof(xp)))
138		return -EFAULT;
139	*data += sizeof(xp);
140	*len -= sizeof(xp);
141	wp = kzalloc(sizeof(*wp), gfp_mask);
142	if (wp == NULL)
143		return -ENOMEM;
144	wp->share_id[0] = le32_to_cpu(xp.share_id[0]);
145	wp->share_id[1] = le32_to_cpu(xp.share_id[1]);
146	wp->share_id[2] = le32_to_cpu(xp.share_id[2]);
147	wp->share_id[3] = le32_to_cpu(xp.share_id[3]);
148	wp->format = le32_to_cpu(xp.format);
149	wp->address.memory = le32_to_cpu(xp.offset);
150	wp->size = le32_to_cpu(xp.size);
151	wp->start = le32_to_cpu(xp.start);
152	wp->loop_start = le32_to_cpu(xp.loop_start);
153	wp->loop_end = le32_to_cpu(xp.loop_end);
154	wp->loop_repeat = le16_to_cpu(xp.loop_repeat);
155	wp->sample_ratio = le32_to_cpu(xp.sample_ratio);
156	wp->attenuation = xp.attenuation;
157	wp->low_note = xp.low_note;
158	wp->high_note = xp.high_note;
159	real_size = snd_seq_iwffff_size(wp->size, wp->format);
160	if (!(wp->format & IWFFFF_WAVE_ROM)) {
161		if ((long)real_size > *len) {
162			kfree(wp);
163			return -ENOMEM;
164		}
165	}
166	if (ops->put_sample) {
167		err = ops->put_sample(ops->private_data, wp,
168				      *data, real_size, atomic);
169		if (err < 0) {
170			kfree(wp);
171			return err;
172		}
173	}
174	if (!(wp->format & IWFFFF_WAVE_ROM)) {
175		*data += real_size;
176		*len -= real_size;
177	}
178	prev = lp->wave;
179	if (prev) {
180		while (prev->next) prev = prev->next;
181		prev->next = wp;
182	} else {
183		lp->wave = wp;
184	}
185	return 0;
186}
187
188static void snd_seq_iwffff_env_free(struct snd_iwffff_ops *ops,
189				    struct iwffff_env *env,
190				    int atomic)
191{
192	struct iwffff_env_record *rec;
193
194	while ((rec = env->record) != NULL) {
195		env->record = rec->next;
196		kfree(rec);
197	}
198}
199
200static void snd_seq_iwffff_wave_free(struct snd_iwffff_ops *ops,
201				     struct iwffff_wave *wave,
202				     int atomic)
203{
204	if (ops->remove_sample)
205		ops->remove_sample(ops->private_data, wave, atomic);
206	kfree(wave);
207}
208
209static void snd_seq_iwffff_instr_free(struct snd_iwffff_ops *ops,
210                                      struct iwffff_instrument *ip,
211                                      int atomic)
212{
213	struct iwffff_layer *layer;
214	struct iwffff_wave *wave;
215
216	while ((layer = ip->layer) != NULL) {
217		ip->layer = layer->next;
218		snd_seq_iwffff_env_free(ops, &layer->penv, atomic);
219		snd_seq_iwffff_env_free(ops, &layer->venv, atomic);
220		while ((wave = layer->wave) != NULL) {
221			layer->wave = wave->next;
222			snd_seq_iwffff_wave_free(ops, wave, atomic);
223		}
224		kfree(layer);
225	}
226}
227
228static int snd_seq_iwffff_put(void *private_data, struct snd_seq_kinstr *instr,
229			      char __user *instr_data, long len, int atomic,
230			      int cmd)
231{
232	struct snd_iwffff_ops *ops = private_data;
233	struct iwffff_instrument *ip;
234	struct iwffff_xinstrument ix;
235	struct iwffff_layer *lp, *prev_lp;
236	struct iwffff_xlayer lx;
237	int err;
238	gfp_t gfp_mask;
239
240	if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
241		return -EINVAL;
242	gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
243	/* copy instrument data */
244	if (len < (long)sizeof(ix))
245		return -EINVAL;
246	if (copy_from_user(&ix, instr_data, sizeof(ix)))
247		return -EFAULT;
248	if (ix.stype != IWFFFF_STRU_INSTR)
249		return -EINVAL;
250	instr_data += sizeof(ix);
251	len -= sizeof(ix);
252	ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
253	ip->exclusion = le16_to_cpu(ix.exclusion);
254	ip->layer_type = le16_to_cpu(ix.layer_type);
255	ip->exclusion_group = le16_to_cpu(ix.exclusion_group);
256	ip->effect1 = ix.effect1;
257	ip->effect1_depth = ix.effect1_depth;
258	ip->effect2 = ix.effect2;
259	ip->effect2_depth = ix.effect2_depth;
260	/* copy layers */
261	prev_lp = NULL;
262	while (len > 0) {
263		if (len < (long)sizeof(struct iwffff_xlayer)) {
264			snd_seq_iwffff_instr_free(ops, ip, atomic);
265			return -EINVAL;
266		}
267		if (copy_from_user(&lx, instr_data, sizeof(lx)))
268			return -EFAULT;
269		instr_data += sizeof(lx);
270		len -= sizeof(lx);
271		if (lx.stype != IWFFFF_STRU_LAYER) {
272			snd_seq_iwffff_instr_free(ops, ip, atomic);
273			return -EINVAL;
274		}
275		lp = kzalloc(sizeof(*lp), gfp_mask);
276		if (lp == NULL) {
277			snd_seq_iwffff_instr_free(ops, ip, atomic);
278			return -ENOMEM;
279		}
280		if (prev_lp) {
281			prev_lp->next = lp;
282		} else {
283			ip->layer = lp;
284		}
285		prev_lp = lp;
286		lp->flags = lx.flags;
287		lp->velocity_mode = lx.velocity_mode;
288		lp->layer_event = lx.layer_event;
289		lp->low_range = lx.low_range;
290		lp->high_range = lx.high_range;
291		lp->pan = lx.pan;
292		lp->pan_freq_scale = lx.pan_freq_scale;
293		lp->attenuation = lx.attenuation;
294		snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo);
295		snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato);
296		lp->freq_scale = le16_to_cpu(lx.freq_scale);
297		lp->freq_center = lx.freq_center;
298		err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP,
299							  lp,
300							  &lp->penv, &lx.penv,
301						          &instr_data, &len,
302						          gfp_mask);
303		if (err < 0) {
304			snd_seq_iwffff_instr_free(ops, ip, atomic);
305			return err;
306		}
307		err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV,
308							  lp,
309							  &lp->venv, &lx.venv,
310						          &instr_data, &len,
311						          gfp_mask);
312		if (err < 0) {
313			snd_seq_iwffff_instr_free(ops, ip, atomic);
314			return err;
315		}
316		while (len > (long)sizeof(__u32)) {
317			__u32 stype;
318
319			if (copy_from_user(&stype, instr_data, sizeof(stype)))
320				return -EFAULT;
321			if (stype != IWFFFF_STRU_WAVE)
322				break;
323			err = snd_seq_iwffff_copy_wave_from_stream(ops,
324								   lp,
325							    	   &instr_data,
326								   &len,
327								   atomic);
328			if (err < 0) {
329				snd_seq_iwffff_instr_free(ops, ip, atomic);
330				return err;
331			}
332		}
333	}
334	return 0;
335}
336
337static void snd_seq_iwffff_copy_lfo_to_stream(struct iwffff_xlfo *fx,
338					      struct iwffff_lfo *fp)
339{
340	fx->freq = cpu_to_le16(fp->freq);
341	fx->depth = cpu_to_le16(fp->depth);
342	fx->sweep = cpu_to_le16(fp->sweep);
343	fp->shape = fx->shape;
344	fp->delay = fx->delay;
345}
346
347static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype,
348					     struct iwffff_layer *lp,
349					     struct iwffff_xenv *ex,
350					     struct iwffff_env *ep,
351					     char __user **data,
352					     long *len)
353{
354	struct iwffff_env_record *rp;
355	struct iwffff_xenv_record rx;
356	struct iwffff_env_point *pp;
357	struct iwffff_xenv_point px;
358	int points_size, idx;
359
360	ex->flags = ep->flags;
361	ex->mode = ep->mode;
362	ex->index = ep->index;
363	for (rp = ep->record; rp; rp = rp->next) {
364		if (*len < (long)sizeof(rx))
365			return -ENOMEM;
366		memset(&rx, 0, sizeof(rx));
367		rx.stype = req_stype;
368		rx.nattack = cpu_to_le16(rp->nattack);
369		rx.nrelease = cpu_to_le16(rp->nrelease);
370		rx.sustain_offset = cpu_to_le16(rp->sustain_offset);
371		rx.sustain_rate = cpu_to_le16(rp->sustain_rate);
372		rx.release_rate = cpu_to_le16(rp->release_rate);
373		rx.hirange = cpu_to_le16(rp->hirange);
374		if (copy_to_user(*data, &rx, sizeof(rx)))
375			return -EFAULT;
376		*data += sizeof(rx);
377		*len -= sizeof(rx);
378		points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
379		if (*len < points_size)
380			return -ENOMEM;
381		pp = (struct iwffff_env_point *)(rp + 1);
382		for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
383			px.offset = cpu_to_le16(pp->offset);
384			px.rate = cpu_to_le16(pp->rate);
385			if (copy_to_user(*data, &px, sizeof(px)))
386				return -EFAULT;
387			*data += sizeof(px);
388			*len -= sizeof(px);
389		}
390	}
391	return 0;
392}
393
394static int snd_seq_iwffff_copy_wave_to_stream(struct snd_iwffff_ops *ops,
395					      struct iwffff_layer *lp,
396					      char __user **data,
397					      long *len,
398					      int atomic)
399{
400	struct iwffff_wave *wp;
401	struct iwffff_xwave xp;
402	int err;
403	unsigned int real_size;
404
405	for (wp = lp->wave; wp; wp = wp->next) {
406		if (*len < (long)sizeof(xp))
407			return -ENOMEM;
408		memset(&xp, 0, sizeof(xp));
409		xp.stype = IWFFFF_STRU_WAVE;
410		xp.share_id[0] = cpu_to_le32(wp->share_id[0]);
411		xp.share_id[1] = cpu_to_le32(wp->share_id[1]);
412		xp.share_id[2] = cpu_to_le32(wp->share_id[2]);
413		xp.share_id[3] = cpu_to_le32(wp->share_id[3]);
414		xp.format = cpu_to_le32(wp->format);
415		if (wp->format & IWFFFF_WAVE_ROM)
416			xp.offset = cpu_to_le32(wp->address.memory);
417		xp.size = cpu_to_le32(wp->size);
418		xp.start = cpu_to_le32(wp->start);
419		xp.loop_start = cpu_to_le32(wp->loop_start);
420		xp.loop_end = cpu_to_le32(wp->loop_end);
421		xp.loop_repeat = cpu_to_le32(wp->loop_repeat);
422		xp.sample_ratio = cpu_to_le32(wp->sample_ratio);
423		xp.attenuation = wp->attenuation;
424		xp.low_note = wp->low_note;
425		xp.high_note = wp->high_note;
426		if (copy_to_user(*data, &xp, sizeof(xp)))
427			return -EFAULT;
428		*data += sizeof(xp);
429		*len -= sizeof(xp);
430		real_size = snd_seq_iwffff_size(wp->size, wp->format);
431		if (!(wp->format & IWFFFF_WAVE_ROM)) {
432			if (*len < (long)real_size)
433				return -ENOMEM;
434		}
435		if (ops->get_sample) {
436			err = ops->get_sample(ops->private_data, wp,
437					      *data, real_size, atomic);
438			if (err < 0)
439				return err;
440		}
441		if (!(wp->format & IWFFFF_WAVE_ROM)) {
442			*data += real_size;
443			*len -= real_size;
444		}
445	}
446	return 0;
447}
448
449static int snd_seq_iwffff_get(void *private_data, struct snd_seq_kinstr *instr,
450			      char __user *instr_data, long len, int atomic, int cmd)
451{
452	struct snd_iwffff_ops *ops = private_data;
453	struct iwffff_instrument *ip;
454	struct iwffff_xinstrument ix;
455	struct iwffff_layer *lp;
456	struct iwffff_xlayer lx;
457	char __user *layer_instr_data;
458	int err;
459
460	if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
461		return -EINVAL;
462	if (len < (long)sizeof(ix))
463		return -ENOMEM;
464	memset(&ix, 0, sizeof(ix));
465	ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
466	ix.stype = IWFFFF_STRU_INSTR;
467	ix.exclusion = cpu_to_le16(ip->exclusion);
468	ix.layer_type = cpu_to_le16(ip->layer_type);
469	ix.exclusion_group = cpu_to_le16(ip->exclusion_group);
470	ix.effect1 = cpu_to_le16(ip->effect1);
471	ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
472	ix.effect2 = ip->effect2;
473	ix.effect2_depth = ip->effect2_depth;
474	if (copy_to_user(instr_data, &ix, sizeof(ix)))
475		return -EFAULT;
476	instr_data += sizeof(ix);
477	len -= sizeof(ix);
478	for (lp = ip->layer; lp; lp = lp->next) {
479		if (len < (long)sizeof(lx))
480			return -ENOMEM;
481		memset(&lx, 0, sizeof(lx));
482		lx.stype = IWFFFF_STRU_LAYER;
483		lx.flags = lp->flags;
484		lx.velocity_mode = lp->velocity_mode;
485		lx.layer_event = lp->layer_event;
486		lx.low_range = lp->low_range;
487		lx.high_range = lp->high_range;
488		lx.pan = lp->pan;
489		lx.pan_freq_scale = lp->pan_freq_scale;
490		lx.attenuation = lp->attenuation;
491		snd_seq_iwffff_copy_lfo_to_stream(&lx.tremolo, &lp->tremolo);
492		snd_seq_iwffff_copy_lfo_to_stream(&lx.vibrato, &lp->vibrato);
493		layer_instr_data = instr_data;
494		instr_data += sizeof(lx);
495		len -= sizeof(lx);
496		err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP,
497							lp,
498							&lx.penv, &lp->penv,
499						        &instr_data, &len);
500		if (err < 0)
501			return err;
502		err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV,
503							lp,
504							&lx.venv, &lp->venv,
505						        &instr_data, &len);
506		if (err < 0)
507			return err;
508		/* layer structure updating is now finished */
509		if (copy_to_user(layer_instr_data, &lx, sizeof(lx)))
510			return -EFAULT;
511		err = snd_seq_iwffff_copy_wave_to_stream(ops,
512							 lp,
513							 &instr_data,
514							 &len,
515							 atomic);
516		if (err < 0)
517			return err;
518	}
519	return 0;
520}
521
522static long snd_seq_iwffff_env_size_in_stream(struct iwffff_env *ep)
523{
524	long result = 0;
525	struct iwffff_env_record *rp;
526
527	for (rp = ep->record; rp; rp = rp->next) {
528		result += sizeof(struct iwffff_xenv_record);
529		result += (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
530	}
531	return 0;
532}
533
534static long snd_seq_iwffff_wave_size_in_stream(struct iwffff_layer *lp)
535{
536	long result = 0;
537	struct iwffff_wave *wp;
538
539	for (wp = lp->wave; wp; wp = wp->next) {
540		result += sizeof(struct iwffff_xwave);
541		if (!(wp->format & IWFFFF_WAVE_ROM))
542			result += wp->size;
543	}
544	return result;
545}
546
547static int snd_seq_iwffff_get_size(void *private_data, struct snd_seq_kinstr *instr,
548				   long *size)
549{
550	long result;
551	struct iwffff_instrument *ip;
552	struct iwffff_layer *lp;
553
554	*size = 0;
555	ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
556	result = sizeof(struct iwffff_xinstrument);
557	for (lp = ip->layer; lp; lp = lp->next) {
558		result += sizeof(struct iwffff_xlayer);
559		result += snd_seq_iwffff_env_size_in_stream(&lp->penv);
560		result += snd_seq_iwffff_env_size_in_stream(&lp->venv);
561		result += snd_seq_iwffff_wave_size_in_stream(lp);
562	}
563	*size = result;
564	return 0;
565}
566
567static int snd_seq_iwffff_remove(void *private_data,
568				 struct snd_seq_kinstr *instr,
569                                 int atomic)
570{
571	struct snd_iwffff_ops *ops = private_data;
572	struct iwffff_instrument *ip;
573
574	ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
575	snd_seq_iwffff_instr_free(ops, ip, atomic);
576	return 0;
577}
578
579static void snd_seq_iwffff_notify(void *private_data,
580				  struct snd_seq_kinstr *instr,
581                                  int what)
582{
583	struct snd_iwffff_ops *ops = private_data;
584
585	if (ops->notify)
586		ops->notify(ops->private_data, instr, what);
587}
588
589int snd_seq_iwffff_init(struct snd_iwffff_ops *ops,
590			void *private_data,
591			struct snd_seq_kinstr_ops *next)
592{
593	memset(ops, 0, sizeof(*ops));
594	ops->private_data = private_data;
595	ops->kops.private_data = ops;
596	ops->kops.add_len = sizeof(struct iwffff_instrument);
597	ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE;
598	ops->kops.put = snd_seq_iwffff_put;
599	ops->kops.get = snd_seq_iwffff_get;
600	ops->kops.get_size = snd_seq_iwffff_get_size;
601	ops->kops.remove = snd_seq_iwffff_remove;
602	ops->kops.notify = snd_seq_iwffff_notify;
603	ops->kops.next = next;
604	return 0;
605}
606
607/*
608 *  Init part
609 */
610
611static int __init alsa_ainstr_iw_init(void)
612{
613	return 0;
614}
615
616static void __exit alsa_ainstr_iw_exit(void)
617{
618}
619
620module_init(alsa_ainstr_iw_init)
621module_exit(alsa_ainstr_iw_exit)
622
623EXPORT_SYMBOL(snd_seq_iwffff_init);
624