Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.12 622 lines 17 kB view raw
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/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> 29 30MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 31MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support."); 32MODULE_LICENSE("GPL"); 33 34static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format) 35{ 36 unsigned int result = size; 37 38 if (format & IWFFFF_WAVE_16BIT) 39 result <<= 1; 40 if (format & IWFFFF_WAVE_STEREO) 41 result <<= 1; 42 return result; 43} 44 45static void snd_seq_iwffff_copy_lfo_from_stream(iwffff_lfo_t *fp, 46 iwffff_xlfo_t *fx) 47{ 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; 53} 54 55static 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 int gfp_mask) 62{ 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; 69 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; 85 } 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); 112 } 113 if (ep->record == NULL) { 114 ep->record = rp; 115 } else { 116 rp_last = rp; 117 } 118 rp_last = rp; 119 } 120 return 0; 121} 122 123static 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) 128{ 129 iwffff_wave_t *wp, *prev; 130 iwffff_xwave_t xp; 131 int err, 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 = kcalloc(1, 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(snd_iwffff_ops_t *ops, 189 iwffff_env_t *env, 190 int atomic) 191{ 192 iwffff_env_record_t *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(snd_iwffff_ops_t *ops, 201 iwffff_wave_t *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(snd_iwffff_ops_t *ops, 210 iwffff_instrument_t *ip, 211 int atomic) 212{ 213 iwffff_layer_t *layer; 214 iwffff_wave_t *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, snd_seq_kinstr_t *instr, 229 char __user *instr_data, long len, int atomic, 230 int cmd) 231{ 232 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data; 233 iwffff_instrument_t *ip; 234 iwffff_xinstrument_t ix; 235 iwffff_layer_t *lp, *prev_lp; 236 iwffff_xlayer_t lx; 237 int err, gfp_mask; 238 239 if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) 240 return -EINVAL; 241 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; 242 /* copy instrument data */ 243 if (len < (long)sizeof(ix)) 244 return -EINVAL; 245 if (copy_from_user(&ix, instr_data, sizeof(ix))) 246 return -EFAULT; 247 if (ix.stype != IWFFFF_STRU_INSTR) 248 return -EINVAL; 249 instr_data += sizeof(ix); 250 len -= sizeof(ix); 251 ip = (iwffff_instrument_t *)KINSTR_DATA(instr); 252 ip->exclusion = le16_to_cpu(ix.exclusion); 253 ip->layer_type = le16_to_cpu(ix.layer_type); 254 ip->exclusion_group = le16_to_cpu(ix.exclusion_group); 255 ip->effect1 = ix.effect1; 256 ip->effect1_depth = ix.effect1_depth; 257 ip->effect2 = ix.effect2; 258 ip->effect2_depth = ix.effect2_depth; 259 /* copy layers */ 260 prev_lp = NULL; 261 while (len > 0) { 262 if (len < (long)sizeof(iwffff_xlayer_t)) { 263 snd_seq_iwffff_instr_free(ops, ip, atomic); 264 return -EINVAL; 265 } 266 if (copy_from_user(&lx, instr_data, sizeof(lx))) 267 return -EFAULT; 268 instr_data += sizeof(lx); 269 len -= sizeof(lx); 270 if (lx.stype != IWFFFF_STRU_LAYER) { 271 snd_seq_iwffff_instr_free(ops, ip, atomic); 272 return -EINVAL; 273 } 274 lp = kcalloc(1, sizeof(*lp), gfp_mask); 275 if (lp == NULL) { 276 snd_seq_iwffff_instr_free(ops, ip, atomic); 277 return -ENOMEM; 278 } 279 if (prev_lp) { 280 prev_lp->next = lp; 281 } else { 282 ip->layer = lp; 283 } 284 prev_lp = lp; 285 lp->flags = lx.flags; 286 lp->velocity_mode = lx.velocity_mode; 287 lp->layer_event = lx.layer_event; 288 lp->low_range = lx.low_range; 289 lp->high_range = lx.high_range; 290 lp->pan = lx.pan; 291 lp->pan_freq_scale = lx.pan_freq_scale; 292 lp->attenuation = lx.attenuation; 293 snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo); 294 snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato); 295 lp->freq_scale = le16_to_cpu(lx.freq_scale); 296 lp->freq_center = lx.freq_center; 297 err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP, 298 lp, 299 &lp->penv, &lx.penv, 300 &instr_data, &len, 301 gfp_mask); 302 if (err < 0) { 303 snd_seq_iwffff_instr_free(ops, ip, atomic); 304 return err; 305 } 306 err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV, 307 lp, 308 &lp->venv, &lx.venv, 309 &instr_data, &len, 310 gfp_mask); 311 if (err < 0) { 312 snd_seq_iwffff_instr_free(ops, ip, atomic); 313 return err; 314 } 315 while (len > (long)sizeof(__u32)) { 316 __u32 stype; 317 318 if (copy_from_user(&stype, instr_data, sizeof(stype))) 319 return -EFAULT; 320 if (stype != IWFFFF_STRU_WAVE) 321 break; 322 err = snd_seq_iwffff_copy_wave_from_stream(ops, 323 lp, 324 &instr_data, 325 &len, 326 atomic); 327 if (err < 0) { 328 snd_seq_iwffff_instr_free(ops, ip, atomic); 329 return err; 330 } 331 } 332 } 333 return 0; 334} 335 336static void snd_seq_iwffff_copy_lfo_to_stream(iwffff_xlfo_t *fx, 337 iwffff_lfo_t *fp) 338{ 339 fx->freq = cpu_to_le16(fp->freq); 340 fx->depth = cpu_to_le16(fp->depth); 341 fx->sweep = cpu_to_le16(fp->sweep); 342 fp->shape = fx->shape; 343 fp->delay = fx->delay; 344} 345 346static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype, 347 iwffff_layer_t *lp, 348 iwffff_xenv_t *ex, 349 iwffff_env_t *ep, 350 char __user **data, 351 long *len) 352{ 353 iwffff_env_record_t *rp; 354 iwffff_xenv_record_t rx; 355 iwffff_env_point_t *pp; 356 iwffff_xenv_point_t px; 357 int points_size, idx; 358 359 ex->flags = ep->flags; 360 ex->mode = ep->mode; 361 ex->index = ep->index; 362 for (rp = ep->record; rp; rp = rp->next) { 363 if (*len < (long)sizeof(rx)) 364 return -ENOMEM; 365 memset(&rx, 0, sizeof(rx)); 366 rx.stype = req_stype; 367 rx.nattack = cpu_to_le16(rp->nattack); 368 rx.nrelease = cpu_to_le16(rp->nrelease); 369 rx.sustain_offset = cpu_to_le16(rp->sustain_offset); 370 rx.sustain_rate = cpu_to_le16(rp->sustain_rate); 371 rx.release_rate = cpu_to_le16(rp->release_rate); 372 rx.hirange = cpu_to_le16(rp->hirange); 373 if (copy_to_user(*data, &rx, sizeof(rx))) 374 return -EFAULT; 375 *data += sizeof(rx); 376 *len -= sizeof(rx); 377 points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16); 378 if (*len < points_size) 379 return -ENOMEM; 380 pp = (iwffff_env_point_t *)(rp + 1); 381 for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) { 382 px.offset = cpu_to_le16(pp->offset); 383 px.rate = cpu_to_le16(pp->rate); 384 if (copy_to_user(*data, &px, sizeof(px))) 385 return -EFAULT; 386 *data += sizeof(px); 387 *len -= sizeof(px); 388 } 389 } 390 return 0; 391} 392 393static int snd_seq_iwffff_copy_wave_to_stream(snd_iwffff_ops_t *ops, 394 iwffff_layer_t *lp, 395 char __user **data, 396 long *len, 397 int atomic) 398{ 399 iwffff_wave_t *wp; 400 iwffff_xwave_t xp; 401 int err; 402 unsigned int real_size; 403 404 for (wp = lp->wave; wp; wp = wp->next) { 405 if (*len < (long)sizeof(xp)) 406 return -ENOMEM; 407 memset(&xp, 0, sizeof(xp)); 408 xp.stype = IWFFFF_STRU_WAVE; 409 xp.share_id[0] = cpu_to_le32(wp->share_id[0]); 410 xp.share_id[1] = cpu_to_le32(wp->share_id[1]); 411 xp.share_id[2] = cpu_to_le32(wp->share_id[2]); 412 xp.share_id[3] = cpu_to_le32(wp->share_id[3]); 413 xp.format = cpu_to_le32(wp->format); 414 if (wp->format & IWFFFF_WAVE_ROM) 415 xp.offset = cpu_to_le32(wp->address.memory); 416 xp.size = cpu_to_le32(wp->size); 417 xp.start = cpu_to_le32(wp->start); 418 xp.loop_start = cpu_to_le32(wp->loop_start); 419 xp.loop_end = cpu_to_le32(wp->loop_end); 420 xp.loop_repeat = cpu_to_le32(wp->loop_repeat); 421 xp.sample_ratio = cpu_to_le32(wp->sample_ratio); 422 xp.attenuation = wp->attenuation; 423 xp.low_note = wp->low_note; 424 xp.high_note = wp->high_note; 425 if (copy_to_user(*data, &xp, sizeof(xp))) 426 return -EFAULT; 427 *data += sizeof(xp); 428 *len -= sizeof(xp); 429 real_size = snd_seq_iwffff_size(wp->size, wp->format); 430 if (!(wp->format & IWFFFF_WAVE_ROM)) { 431 if (*len < (long)real_size) 432 return -ENOMEM; 433 } 434 if (ops->get_sample) { 435 err = ops->get_sample(ops->private_data, wp, 436 *data, real_size, atomic); 437 if (err < 0) 438 return err; 439 } 440 if (!(wp->format & IWFFFF_WAVE_ROM)) { 441 *data += real_size; 442 *len -= real_size; 443 } 444 } 445 return 0; 446} 447 448static int snd_seq_iwffff_get(void *private_data, snd_seq_kinstr_t *instr, 449 char __user *instr_data, long len, int atomic, int cmd) 450{ 451 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data; 452 iwffff_instrument_t *ip; 453 iwffff_xinstrument_t ix; 454 iwffff_layer_t *lp; 455 iwffff_xlayer_t lx; 456 char __user *layer_instr_data; 457 int err; 458 459 if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) 460 return -EINVAL; 461 if (len < (long)sizeof(ix)) 462 return -ENOMEM; 463 memset(&ix, 0, sizeof(ix)); 464 ip = (iwffff_instrument_t *)KINSTR_DATA(instr); 465 ix.stype = IWFFFF_STRU_INSTR; 466 ix.exclusion = cpu_to_le16(ip->exclusion); 467 ix.layer_type = cpu_to_le16(ip->layer_type); 468 ix.exclusion_group = cpu_to_le16(ip->exclusion_group); 469 ix.effect1 = cpu_to_le16(ip->effect1); 470 ix.effect1_depth = cpu_to_le16(ip->effect1_depth); 471 ix.effect2 = ip->effect2; 472 ix.effect2_depth = ip->effect2_depth; 473 if (copy_to_user(instr_data, &ix, sizeof(ix))) 474 return -EFAULT; 475 instr_data += sizeof(ix); 476 len -= sizeof(ix); 477 for (lp = ip->layer; lp; lp = lp->next) { 478 if (len < (long)sizeof(lx)) 479 return -ENOMEM; 480 memset(&lx, 0, sizeof(lx)); 481 lx.stype = IWFFFF_STRU_LAYER; 482 lx.flags = lp->flags; 483 lx.velocity_mode = lp->velocity_mode; 484 lx.layer_event = lp->layer_event; 485 lx.low_range = lp->low_range; 486 lx.high_range = lp->high_range; 487 lx.pan = lp->pan; 488 lx.pan_freq_scale = lp->pan_freq_scale; 489 lx.attenuation = lp->attenuation; 490 snd_seq_iwffff_copy_lfo_to_stream(&lx.tremolo, &lp->tremolo); 491 snd_seq_iwffff_copy_lfo_to_stream(&lx.vibrato, &lp->vibrato); 492 layer_instr_data = instr_data; 493 instr_data += sizeof(lx); 494 len -= sizeof(lx); 495 err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP, 496 lp, 497 &lx.penv, &lp->penv, 498 &instr_data, &len); 499 if (err < 0) 500 return err; 501 err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV, 502 lp, 503 &lx.venv, &lp->venv, 504 &instr_data, &len); 505 if (err < 0) 506 return err; 507 /* layer structure updating is now finished */ 508 if (copy_to_user(layer_instr_data, &lx, sizeof(lx))) 509 return -EFAULT; 510 err = snd_seq_iwffff_copy_wave_to_stream(ops, 511 lp, 512 &instr_data, 513 &len, 514 atomic); 515 if (err < 0) 516 return err; 517 } 518 return 0; 519} 520 521static long snd_seq_iwffff_env_size_in_stream(iwffff_env_t *ep) 522{ 523 long result = 0; 524 iwffff_env_record_t *rp; 525 526 for (rp = ep->record; rp; rp = rp->next) { 527 result += sizeof(iwffff_xenv_record_t); 528 result += (rp->nattack + rp->nrelease) * 2 * sizeof(__u16); 529 } 530 return 0; 531} 532 533static long snd_seq_iwffff_wave_size_in_stream(iwffff_layer_t *lp) 534{ 535 long result = 0; 536 iwffff_wave_t *wp; 537 538 for (wp = lp->wave; wp; wp = wp->next) { 539 result += sizeof(iwffff_xwave_t); 540 if (!(wp->format & IWFFFF_WAVE_ROM)) 541 result += wp->size; 542 } 543 return result; 544} 545 546static int snd_seq_iwffff_get_size(void *private_data, snd_seq_kinstr_t *instr, 547 long *size) 548{ 549 long result; 550 iwffff_instrument_t *ip; 551 iwffff_layer_t *lp; 552 553 *size = 0; 554 ip = (iwffff_instrument_t *)KINSTR_DATA(instr); 555 result = sizeof(iwffff_xinstrument_t); 556 for (lp = ip->layer; lp; lp = lp->next) { 557 result += sizeof(iwffff_xlayer_t); 558 result += snd_seq_iwffff_env_size_in_stream(&lp->penv); 559 result += snd_seq_iwffff_env_size_in_stream(&lp->venv); 560 result += snd_seq_iwffff_wave_size_in_stream(lp); 561 } 562 *size = result; 563 return 0; 564} 565 566static int snd_seq_iwffff_remove(void *private_data, 567 snd_seq_kinstr_t *instr, 568 int atomic) 569{ 570 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data; 571 iwffff_instrument_t *ip; 572 573 ip = (iwffff_instrument_t *)KINSTR_DATA(instr); 574 snd_seq_iwffff_instr_free(ops, ip, atomic); 575 return 0; 576} 577 578static void snd_seq_iwffff_notify(void *private_data, 579 snd_seq_kinstr_t *instr, 580 int what) 581{ 582 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data; 583 584 if (ops->notify) 585 ops->notify(ops->private_data, instr, what); 586} 587 588int snd_seq_iwffff_init(snd_iwffff_ops_t *ops, 589 void *private_data, 590 snd_seq_kinstr_ops_t *next) 591{ 592 memset(ops, 0, sizeof(*ops)); 593 ops->private_data = private_data; 594 ops->kops.private_data = ops; 595 ops->kops.add_len = sizeof(iwffff_instrument_t); 596 ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE; 597 ops->kops.put = snd_seq_iwffff_put; 598 ops->kops.get = snd_seq_iwffff_get; 599 ops->kops.get_size = snd_seq_iwffff_get_size; 600 ops->kops.remove = snd_seq_iwffff_remove; 601 ops->kops.notify = snd_seq_iwffff_notify; 602 ops->kops.next = next; 603 return 0; 604} 605 606/* 607 * Init part 608 */ 609 610static int __init alsa_ainstr_iw_init(void) 611{ 612 return 0; 613} 614 615static void __exit alsa_ainstr_iw_exit(void) 616{ 617} 618 619module_init(alsa_ainstr_iw_init) 620module_exit(alsa_ainstr_iw_exit) 621 622EXPORT_SYMBOL(snd_seq_iwffff_init);