[ALSA] Changed Jaroslav Kysela's e-mail from perex@suse.cz to perex@perex.cz
[linux-2.6.git] / sound / core / seq / instr / ainstr_iw.c
1 /*
2  *   IWFFFF - AMD InterWave (tm) - Instrument routines
3  *   Copyright (c) 1999 by Jaroslav Kysela <perex@perex.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
29 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
30 MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support.");
31 MODULE_LICENSE("GPL");
32
33 static 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
44 static 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
54 static 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
122 static 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
188 static 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                                     
200 static 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
209 static 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
228 static 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
337 static 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
347 static 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
394 static 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
449 static 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
522 static 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
534 static 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
547 static 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
567 static 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
579 static 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
589 int 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
611 static int __init alsa_ainstr_iw_init(void)
612 {
613         return 0;
614 }
615
616 static void __exit alsa_ainstr_iw_exit(void)
617 {
618 }
619
620 module_init(alsa_ainstr_iw_init)
621 module_exit(alsa_ainstr_iw_exit)
622
623 EXPORT_SYMBOL(snd_seq_iwffff_init);