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