| .. | .. |
|---|
| 30 | 30 | #include <sound/soc-topology.h> |
|---|
| 31 | 31 | #include <sound/tlv.h> |
|---|
| 32 | 32 | |
|---|
| 33 | +#define SOC_TPLG_MAGIC_BIG_ENDIAN 0x436F5341 /* ASoC in reverse */ |
|---|
| 34 | + |
|---|
| 33 | 35 | /* |
|---|
| 34 | 36 | * We make several passes over the data (since it wont necessarily be ordered) |
|---|
| 35 | 37 | * and process objects in the following order. This guarantees the component |
|---|
| .. | .. |
|---|
| 78 | 80 | |
|---|
| 79 | 81 | static int soc_tplg_process_headers(struct soc_tplg *tplg); |
|---|
| 80 | 82 | static void soc_tplg_complete(struct soc_tplg *tplg); |
|---|
| 81 | | -struct snd_soc_dapm_widget * |
|---|
| 82 | | -snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, |
|---|
| 83 | | - const struct snd_soc_dapm_widget *widget); |
|---|
| 84 | | -struct snd_soc_dapm_widget * |
|---|
| 85 | | -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
|---|
| 86 | | - const struct snd_soc_dapm_widget *widget); |
|---|
| 83 | +static void soc_tplg_denum_remove_texts(struct soc_enum *se); |
|---|
| 84 | +static void soc_tplg_denum_remove_values(struct soc_enum *se); |
|---|
| 87 | 85 | |
|---|
| 88 | 86 | /* check we dont overflow the data for this control chunk */ |
|---|
| 89 | 87 | static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size, |
|---|
| .. | .. |
|---|
| 197 | 195 | int i; |
|---|
| 198 | 196 | |
|---|
| 199 | 197 | for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { |
|---|
| 200 | | - if (chan[i].id == map) |
|---|
| 201 | | - return chan[i].reg; |
|---|
| 198 | + if (le32_to_cpu(chan[i].id) == map) |
|---|
| 199 | + return le32_to_cpu(chan[i].reg); |
|---|
| 202 | 200 | } |
|---|
| 203 | 201 | |
|---|
| 204 | 202 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 210 | 208 | int i; |
|---|
| 211 | 209 | |
|---|
| 212 | 210 | for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { |
|---|
| 213 | | - if (chan[i].id == map) |
|---|
| 214 | | - return chan[i].shift; |
|---|
| 211 | + if (le32_to_cpu(chan[i].id) == map) |
|---|
| 212 | + return le32_to_cpu(chan[i].shift); |
|---|
| 215 | 213 | } |
|---|
| 216 | 214 | |
|---|
| 217 | 215 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 248 | 246 | } |
|---|
| 249 | 247 | |
|---|
| 250 | 248 | /* pass vendor data to component driver for processing */ |
|---|
| 251 | | -static int soc_tplg_vendor_load_(struct soc_tplg *tplg, |
|---|
| 252 | | - struct snd_soc_tplg_hdr *hdr) |
|---|
| 249 | +static int soc_tplg_vendor_load(struct soc_tplg *tplg, |
|---|
| 250 | + struct snd_soc_tplg_hdr *hdr) |
|---|
| 253 | 251 | { |
|---|
| 254 | 252 | int ret = 0; |
|---|
| 255 | 253 | |
|---|
| 256 | | - if (tplg->comp && tplg->ops && tplg->ops->vendor_load) |
|---|
| 254 | + if (tplg->ops && tplg->ops->vendor_load) |
|---|
| 257 | 255 | ret = tplg->ops->vendor_load(tplg->comp, tplg->index, hdr); |
|---|
| 258 | 256 | else { |
|---|
| 259 | 257 | dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n", |
|---|
| .. | .. |
|---|
| 270 | 268 | return ret; |
|---|
| 271 | 269 | } |
|---|
| 272 | 270 | |
|---|
| 273 | | -/* pass vendor data to component driver for processing */ |
|---|
| 274 | | -static int soc_tplg_vendor_load(struct soc_tplg *tplg, |
|---|
| 275 | | - struct snd_soc_tplg_hdr *hdr) |
|---|
| 276 | | -{ |
|---|
| 277 | | - if (tplg->pass != SOC_TPLG_PASS_VENDOR) |
|---|
| 278 | | - return 0; |
|---|
| 279 | | - |
|---|
| 280 | | - return soc_tplg_vendor_load_(tplg, hdr); |
|---|
| 281 | | -} |
|---|
| 282 | | - |
|---|
| 283 | 271 | /* optionally pass new dynamic widget to component driver. This is mainly for |
|---|
| 284 | 272 | * external widgets where we can assign private data/ops */ |
|---|
| 285 | 273 | static int soc_tplg_widget_load(struct soc_tplg *tplg, |
|---|
| 286 | 274 | struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) |
|---|
| 287 | 275 | { |
|---|
| 288 | | - if (tplg->comp && tplg->ops && tplg->ops->widget_load) |
|---|
| 276 | + if (tplg->ops && tplg->ops->widget_load) |
|---|
| 289 | 277 | return tplg->ops->widget_load(tplg->comp, tplg->index, w, |
|---|
| 290 | 278 | tplg_w); |
|---|
| 291 | 279 | |
|---|
| .. | .. |
|---|
| 297 | 285 | static int soc_tplg_widget_ready(struct soc_tplg *tplg, |
|---|
| 298 | 286 | struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) |
|---|
| 299 | 287 | { |
|---|
| 300 | | - if (tplg->comp && tplg->ops && tplg->ops->widget_ready) |
|---|
| 288 | + if (tplg->ops && tplg->ops->widget_ready) |
|---|
| 301 | 289 | return tplg->ops->widget_ready(tplg->comp, tplg->index, w, |
|---|
| 302 | 290 | tplg_w); |
|---|
| 303 | 291 | |
|---|
| .. | .. |
|---|
| 309 | 297 | struct snd_soc_dai_driver *dai_drv, |
|---|
| 310 | 298 | struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) |
|---|
| 311 | 299 | { |
|---|
| 312 | | - if (tplg->comp && tplg->ops && tplg->ops->dai_load) |
|---|
| 300 | + if (tplg->ops && tplg->ops->dai_load) |
|---|
| 313 | 301 | return tplg->ops->dai_load(tplg->comp, tplg->index, dai_drv, |
|---|
| 314 | 302 | pcm, dai); |
|---|
| 315 | 303 | |
|---|
| .. | .. |
|---|
| 320 | 308 | static int soc_tplg_dai_link_load(struct soc_tplg *tplg, |
|---|
| 321 | 309 | struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg) |
|---|
| 322 | 310 | { |
|---|
| 323 | | - if (tplg->comp && tplg->ops && tplg->ops->link_load) |
|---|
| 311 | + if (tplg->ops && tplg->ops->link_load) |
|---|
| 324 | 312 | return tplg->ops->link_load(tplg->comp, tplg->index, link, cfg); |
|---|
| 325 | 313 | |
|---|
| 326 | 314 | return 0; |
|---|
| .. | .. |
|---|
| 329 | 317 | /* tell the component driver that all firmware has been loaded in this request */ |
|---|
| 330 | 318 | static void soc_tplg_complete(struct soc_tplg *tplg) |
|---|
| 331 | 319 | { |
|---|
| 332 | | - if (tplg->comp && tplg->ops && tplg->ops->complete) |
|---|
| 320 | + if (tplg->ops && tplg->ops->complete) |
|---|
| 333 | 321 | tplg->ops->complete(tplg->comp); |
|---|
| 334 | 322 | } |
|---|
| 335 | 323 | |
|---|
| .. | .. |
|---|
| 382 | 370 | if (dobj->ops && dobj->ops->control_unload) |
|---|
| 383 | 371 | dobj->ops->control_unload(comp, dobj); |
|---|
| 384 | 372 | |
|---|
| 385 | | - if (sm->dobj.control.kcontrol->tlv.p) |
|---|
| 386 | | - p = sm->dobj.control.kcontrol->tlv.p; |
|---|
| 387 | | - snd_ctl_remove(card, sm->dobj.control.kcontrol); |
|---|
| 388 | | - list_del(&sm->dobj.list); |
|---|
| 373 | + if (dobj->control.kcontrol->tlv.p) |
|---|
| 374 | + p = dobj->control.kcontrol->tlv.p; |
|---|
| 375 | + snd_ctl_remove(card, dobj->control.kcontrol); |
|---|
| 376 | + list_del(&dobj->list); |
|---|
| 389 | 377 | kfree(sm); |
|---|
| 390 | 378 | kfree(p); |
|---|
| 391 | 379 | } |
|---|
| .. | .. |
|---|
| 396 | 384 | { |
|---|
| 397 | 385 | struct snd_card *card = comp->card->snd_card; |
|---|
| 398 | 386 | struct soc_enum *se = container_of(dobj, struct soc_enum, dobj); |
|---|
| 399 | | - int i; |
|---|
| 400 | 387 | |
|---|
| 401 | 388 | if (pass != SOC_TPLG_PASS_MIXER) |
|---|
| 402 | 389 | return; |
|---|
| .. | .. |
|---|
| 404 | 391 | if (dobj->ops && dobj->ops->control_unload) |
|---|
| 405 | 392 | dobj->ops->control_unload(comp, dobj); |
|---|
| 406 | 393 | |
|---|
| 407 | | - snd_ctl_remove(card, se->dobj.control.kcontrol); |
|---|
| 408 | | - list_del(&se->dobj.list); |
|---|
| 394 | + snd_ctl_remove(card, dobj->control.kcontrol); |
|---|
| 395 | + list_del(&dobj->list); |
|---|
| 409 | 396 | |
|---|
| 410 | | - kfree(se->dobj.control.dvalues); |
|---|
| 411 | | - for (i = 0; i < se->items; i++) |
|---|
| 412 | | - kfree(se->dobj.control.dtexts[i]); |
|---|
| 397 | + soc_tplg_denum_remove_values(se); |
|---|
| 398 | + soc_tplg_denum_remove_texts(se); |
|---|
| 413 | 399 | kfree(se); |
|---|
| 414 | 400 | } |
|---|
| 415 | 401 | |
|---|
| .. | .. |
|---|
| 427 | 413 | if (dobj->ops && dobj->ops->control_unload) |
|---|
| 428 | 414 | dobj->ops->control_unload(comp, dobj); |
|---|
| 429 | 415 | |
|---|
| 430 | | - snd_ctl_remove(card, sb->dobj.control.kcontrol); |
|---|
| 431 | | - list_del(&sb->dobj.list); |
|---|
| 416 | + snd_ctl_remove(card, dobj->control.kcontrol); |
|---|
| 417 | + list_del(&dobj->list); |
|---|
| 432 | 418 | kfree(sb); |
|---|
| 419 | +} |
|---|
| 420 | + |
|---|
| 421 | +/* remove a route */ |
|---|
| 422 | +static void remove_route(struct snd_soc_component *comp, |
|---|
| 423 | + struct snd_soc_dobj *dobj, int pass) |
|---|
| 424 | +{ |
|---|
| 425 | + struct snd_soc_dapm_route *route = |
|---|
| 426 | + container_of(dobj, struct snd_soc_dapm_route, dobj); |
|---|
| 427 | + |
|---|
| 428 | + if (pass != SOC_TPLG_PASS_GRAPH) |
|---|
| 429 | + return; |
|---|
| 430 | + |
|---|
| 431 | + if (dobj->ops && dobj->ops->dapm_route_unload) |
|---|
| 432 | + dobj->ops->dapm_route_unload(comp, dobj); |
|---|
| 433 | + |
|---|
| 434 | + list_del(&dobj->list); |
|---|
| 435 | + kfree(route); |
|---|
| 433 | 436 | } |
|---|
| 434 | 437 | |
|---|
| 435 | 438 | /* remove a widget and it's kcontrols - routes must be removed first */ |
|---|
| .. | .. |
|---|
| 460 | 463 | struct snd_kcontrol *kcontrol = w->kcontrols[i]; |
|---|
| 461 | 464 | struct soc_enum *se = |
|---|
| 462 | 465 | (struct soc_enum *)kcontrol->private_value; |
|---|
| 463 | | - int j; |
|---|
| 464 | 466 | |
|---|
| 465 | 467 | snd_ctl_remove(card, kcontrol); |
|---|
| 466 | 468 | |
|---|
| 467 | | - kfree(se->dobj.control.dvalues); |
|---|
| 468 | | - for (j = 0; j < se->items; j++) |
|---|
| 469 | | - kfree(se->dobj.control.dtexts[j]); |
|---|
| 469 | + /* free enum kcontrol's dvalues and dtexts */ |
|---|
| 470 | + soc_tplg_denum_remove_values(se); |
|---|
| 471 | + soc_tplg_denum_remove_texts(se); |
|---|
| 470 | 472 | |
|---|
| 471 | 473 | kfree(se); |
|---|
| 472 | 474 | kfree(w->kcontrol_news[i].name); |
|---|
| .. | .. |
|---|
| 493 | 495 | free_news: |
|---|
| 494 | 496 | kfree(w->kcontrol_news); |
|---|
| 495 | 497 | |
|---|
| 498 | + list_del(&dobj->list); |
|---|
| 499 | + |
|---|
| 496 | 500 | /* widget w is freed by soc-dapm.c */ |
|---|
| 497 | 501 | } |
|---|
| 498 | 502 | |
|---|
| .. | .. |
|---|
| 502 | 506 | { |
|---|
| 503 | 507 | struct snd_soc_dai_driver *dai_drv = |
|---|
| 504 | 508 | container_of(dobj, struct snd_soc_dai_driver, dobj); |
|---|
| 509 | + struct snd_soc_dai *dai, *_dai; |
|---|
| 505 | 510 | |
|---|
| 506 | 511 | if (pass != SOC_TPLG_PASS_PCM_DAI) |
|---|
| 507 | 512 | return; |
|---|
| .. | .. |
|---|
| 509 | 514 | if (dobj->ops && dobj->ops->dai_unload) |
|---|
| 510 | 515 | dobj->ops->dai_unload(comp, dobj); |
|---|
| 511 | 516 | |
|---|
| 517 | + for_each_component_dais_safe(comp, dai, _dai) |
|---|
| 518 | + if (dai->driver == dai_drv) |
|---|
| 519 | + snd_soc_unregister_dai(dai); |
|---|
| 520 | + |
|---|
| 521 | + kfree(dai_drv->playback.stream_name); |
|---|
| 522 | + kfree(dai_drv->capture.stream_name); |
|---|
| 512 | 523 | kfree(dai_drv->name); |
|---|
| 513 | 524 | list_del(&dobj->list); |
|---|
| 514 | 525 | kfree(dai_drv); |
|---|
| .. | .. |
|---|
| 527 | 538 | if (dobj->ops && dobj->ops->link_unload) |
|---|
| 528 | 539 | dobj->ops->link_unload(comp, dobj); |
|---|
| 529 | 540 | |
|---|
| 541 | + list_del(&dobj->list); |
|---|
| 542 | + snd_soc_remove_pcm_runtime(comp->card, |
|---|
| 543 | + snd_soc_get_pcm_runtime(comp->card, link)); |
|---|
| 544 | + |
|---|
| 530 | 545 | kfree(link->name); |
|---|
| 531 | 546 | kfree(link->stream_name); |
|---|
| 532 | | - kfree(link->cpu_dai_name); |
|---|
| 533 | | - |
|---|
| 534 | | - list_del(&dobj->list); |
|---|
| 535 | | - snd_soc_remove_dai_link(comp->card, link); |
|---|
| 547 | + kfree(link->cpus->dai_name); |
|---|
| 536 | 548 | kfree(link); |
|---|
| 549 | +} |
|---|
| 550 | + |
|---|
| 551 | +/* unload dai link */ |
|---|
| 552 | +static void remove_backend_link(struct snd_soc_component *comp, |
|---|
| 553 | + struct snd_soc_dobj *dobj, int pass) |
|---|
| 554 | +{ |
|---|
| 555 | + if (pass != SOC_TPLG_PASS_LINK) |
|---|
| 556 | + return; |
|---|
| 557 | + |
|---|
| 558 | + if (dobj->ops && dobj->ops->link_unload) |
|---|
| 559 | + dobj->ops->link_unload(comp, dobj); |
|---|
| 560 | + |
|---|
| 561 | + /* |
|---|
| 562 | + * We don't free the link here as what remove_link() do since BE |
|---|
| 563 | + * links are not allocated by topology. |
|---|
| 564 | + * We however need to reset the dobj type to its initial values |
|---|
| 565 | + */ |
|---|
| 566 | + dobj->type = SND_SOC_DOBJ_NONE; |
|---|
| 567 | + list_del(&dobj->list); |
|---|
| 537 | 568 | } |
|---|
| 538 | 569 | |
|---|
| 539 | 570 | /* bind a kcontrol to it's IO handlers */ |
|---|
| .. | .. |
|---|
| 545 | 576 | const struct snd_soc_tplg_bytes_ext_ops *ext_ops; |
|---|
| 546 | 577 | int num_ops, i; |
|---|
| 547 | 578 | |
|---|
| 548 | | - if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES |
|---|
| 579 | + if (le32_to_cpu(hdr->ops.info) == SND_SOC_TPLG_CTL_BYTES |
|---|
| 549 | 580 | && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER |
|---|
| 550 | | - && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
|---|
| 581 | + && (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|---|
| 582 | + || k->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) |
|---|
| 551 | 583 | && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { |
|---|
| 552 | 584 | struct soc_bytes_ext *sbe; |
|---|
| 553 | 585 | struct snd_soc_tplg_bytes_control *be; |
|---|
| .. | .. |
|---|
| 561 | 593 | k->info = snd_soc_bytes_info_ext; |
|---|
| 562 | 594 | k->tlv.c = snd_soc_bytes_tlv_callback; |
|---|
| 563 | 595 | |
|---|
| 596 | + /* |
|---|
| 597 | + * When a topology-based implementation abuses the |
|---|
| 598 | + * control interface and uses bytes_ext controls of |
|---|
| 599 | + * more than 512 bytes, we need to disable the size |
|---|
| 600 | + * checks, otherwise accesses to such controls will |
|---|
| 601 | + * return an -EINVAL error and prevent the card from |
|---|
| 602 | + * being configured. |
|---|
| 603 | + */ |
|---|
| 604 | + if (IS_ENABLED(CONFIG_SND_CTL_VALIDATION) && sbe->max > 512) |
|---|
| 605 | + k->access |= SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK; |
|---|
| 606 | + |
|---|
| 564 | 607 | ext_ops = tplg->bytes_ext_ops; |
|---|
| 565 | 608 | num_ops = tplg->bytes_ext_ops_count; |
|---|
| 566 | 609 | for (i = 0; i < num_ops; i++) { |
|---|
| 567 | | - if (!sbe->put && ext_ops[i].id == be->ext_ops.put) |
|---|
| 610 | + if (!sbe->put && |
|---|
| 611 | + ext_ops[i].id == le32_to_cpu(be->ext_ops.put)) |
|---|
| 568 | 612 | sbe->put = ext_ops[i].put; |
|---|
| 569 | | - if (!sbe->get && ext_ops[i].id == be->ext_ops.get) |
|---|
| 613 | + if (!sbe->get && |
|---|
| 614 | + ext_ops[i].id == le32_to_cpu(be->ext_ops.get)) |
|---|
| 570 | 615 | sbe->get = ext_ops[i].get; |
|---|
| 571 | 616 | } |
|---|
| 572 | 617 | |
|---|
| 573 | | - if (sbe->put && sbe->get) |
|---|
| 574 | | - return 0; |
|---|
| 575 | | - else |
|---|
| 618 | + if ((k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) && !sbe->get) |
|---|
| 576 | 619 | return -EINVAL; |
|---|
| 620 | + if ((k->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) && !sbe->put) |
|---|
| 621 | + return -EINVAL; |
|---|
| 622 | + return 0; |
|---|
| 577 | 623 | } |
|---|
| 578 | 624 | |
|---|
| 579 | 625 | /* try and map vendor specific kcontrol handlers first */ |
|---|
| .. | .. |
|---|
| 581 | 627 | num_ops = tplg->io_ops_count; |
|---|
| 582 | 628 | for (i = 0; i < num_ops; i++) { |
|---|
| 583 | 629 | |
|---|
| 584 | | - if (k->put == NULL && ops[i].id == hdr->ops.put) |
|---|
| 630 | + if (k->put == NULL && ops[i].id == le32_to_cpu(hdr->ops.put)) |
|---|
| 585 | 631 | k->put = ops[i].put; |
|---|
| 586 | | - if (k->get == NULL && ops[i].id == hdr->ops.get) |
|---|
| 632 | + if (k->get == NULL && ops[i].id == le32_to_cpu(hdr->ops.get)) |
|---|
| 587 | 633 | k->get = ops[i].get; |
|---|
| 588 | | - if (k->info == NULL && ops[i].id == hdr->ops.info) |
|---|
| 634 | + if (k->info == NULL && ops[i].id == le32_to_cpu(hdr->ops.info)) |
|---|
| 589 | 635 | k->info = ops[i].info; |
|---|
| 590 | 636 | } |
|---|
| 591 | 637 | |
|---|
| .. | .. |
|---|
| 598 | 644 | num_ops = ARRAY_SIZE(io_ops); |
|---|
| 599 | 645 | for (i = 0; i < num_ops; i++) { |
|---|
| 600 | 646 | |
|---|
| 601 | | - if (k->put == NULL && ops[i].id == hdr->ops.put) |
|---|
| 647 | + if (k->put == NULL && ops[i].id == le32_to_cpu(hdr->ops.put)) |
|---|
| 602 | 648 | k->put = ops[i].put; |
|---|
| 603 | | - if (k->get == NULL && ops[i].id == hdr->ops.get) |
|---|
| 649 | + if (k->get == NULL && ops[i].id == le32_to_cpu(hdr->ops.get)) |
|---|
| 604 | 650 | k->get = ops[i].get; |
|---|
| 605 | | - if (k->info == NULL && ops[i].id == hdr->ops.info) |
|---|
| 651 | + if (k->info == NULL && ops[i].id == le32_to_cpu(hdr->ops.info)) |
|---|
| 606 | 652 | k->info = ops[i].info; |
|---|
| 607 | 653 | } |
|---|
| 608 | 654 | |
|---|
| .. | .. |
|---|
| 641 | 687 | static int soc_tplg_init_kcontrol(struct soc_tplg *tplg, |
|---|
| 642 | 688 | struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr) |
|---|
| 643 | 689 | { |
|---|
| 644 | | - if (tplg->comp && tplg->ops && tplg->ops->control_load) |
|---|
| 690 | + if (tplg->ops && tplg->ops->control_load) |
|---|
| 645 | 691 | return tplg->ops->control_load(tplg->comp, tplg->index, k, |
|---|
| 646 | 692 | hdr); |
|---|
| 647 | 693 | |
|---|
| .. | .. |
|---|
| 661 | 707 | |
|---|
| 662 | 708 | p[0] = SNDRV_CTL_TLVT_DB_SCALE; |
|---|
| 663 | 709 | p[1] = item_len; |
|---|
| 664 | | - p[2] = scale->min; |
|---|
| 665 | | - p[3] = (scale->step & TLV_DB_SCALE_MASK) |
|---|
| 666 | | - | (scale->mute ? TLV_DB_SCALE_MUTE : 0); |
|---|
| 710 | + p[2] = le32_to_cpu(scale->min); |
|---|
| 711 | + p[3] = (le32_to_cpu(scale->step) & TLV_DB_SCALE_MASK) |
|---|
| 712 | + | (le32_to_cpu(scale->mute) ? TLV_DB_SCALE_MUTE : 0); |
|---|
| 667 | 713 | |
|---|
| 668 | 714 | kc->tlv.p = (void *)p; |
|---|
| 669 | 715 | return 0; |
|---|
| .. | .. |
|---|
| 673 | 719 | struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc) |
|---|
| 674 | 720 | { |
|---|
| 675 | 721 | struct snd_soc_tplg_ctl_tlv *tplg_tlv; |
|---|
| 722 | + u32 access = le32_to_cpu(tc->access); |
|---|
| 676 | 723 | |
|---|
| 677 | | - if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)) |
|---|
| 724 | + if (!(access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)) |
|---|
| 678 | 725 | return 0; |
|---|
| 679 | 726 | |
|---|
| 680 | | - if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { |
|---|
| 727 | + if (!(access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { |
|---|
| 681 | 728 | tplg_tlv = &tc->tlv; |
|---|
| 682 | | - switch (tplg_tlv->type) { |
|---|
| 729 | + switch (le32_to_cpu(tplg_tlv->type)) { |
|---|
| 683 | 730 | case SNDRV_CTL_TLVT_DB_SCALE: |
|---|
| 684 | 731 | return soc_tplg_create_tlv_db_scale(tplg, kc, |
|---|
| 685 | 732 | &tplg_tlv->scale); |
|---|
| .. | .. |
|---|
| 707 | 754 | struct snd_soc_tplg_bytes_control *be; |
|---|
| 708 | 755 | struct soc_bytes_ext *sbe; |
|---|
| 709 | 756 | struct snd_kcontrol_new kc; |
|---|
| 710 | | - int i, err; |
|---|
| 757 | + int i; |
|---|
| 758 | + int err = 0; |
|---|
| 711 | 759 | |
|---|
| 712 | 760 | if (soc_tplg_check_elem_count(tplg, |
|---|
| 713 | 761 | sizeof(struct snd_soc_tplg_bytes_control), count, |
|---|
| .. | .. |
|---|
| 730 | 778 | return -ENOMEM; |
|---|
| 731 | 779 | |
|---|
| 732 | 780 | tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + |
|---|
| 733 | | - be->priv.size); |
|---|
| 781 | + le32_to_cpu(be->priv.size)); |
|---|
| 734 | 782 | |
|---|
| 735 | 783 | dev_dbg(tplg->dev, |
|---|
| 736 | 784 | "ASoC: adding bytes kcontrol %s with access 0x%x\n", |
|---|
| .. | .. |
|---|
| 740 | 788 | kc.name = be->hdr.name; |
|---|
| 741 | 789 | kc.private_value = (long)sbe; |
|---|
| 742 | 790 | kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
|---|
| 743 | | - kc.access = be->hdr.access; |
|---|
| 791 | + kc.access = le32_to_cpu(be->hdr.access); |
|---|
| 744 | 792 | |
|---|
| 745 | | - sbe->max = be->max; |
|---|
| 793 | + sbe->max = le32_to_cpu(be->max); |
|---|
| 746 | 794 | sbe->dobj.type = SND_SOC_DOBJ_BYTES; |
|---|
| 747 | 795 | sbe->dobj.ops = tplg->ops; |
|---|
| 748 | 796 | INIT_LIST_HEAD(&sbe->dobj.list); |
|---|
| .. | .. |
|---|
| 752 | 800 | if (err) { |
|---|
| 753 | 801 | soc_control_err(tplg, &be->hdr, be->hdr.name); |
|---|
| 754 | 802 | kfree(sbe); |
|---|
| 755 | | - continue; |
|---|
| 803 | + break; |
|---|
| 756 | 804 | } |
|---|
| 757 | 805 | |
|---|
| 758 | 806 | /* pass control to driver for optional further init */ |
|---|
| .. | .. |
|---|
| 762 | 810 | dev_err(tplg->dev, "ASoC: failed to init %s\n", |
|---|
| 763 | 811 | be->hdr.name); |
|---|
| 764 | 812 | kfree(sbe); |
|---|
| 765 | | - continue; |
|---|
| 813 | + break; |
|---|
| 766 | 814 | } |
|---|
| 767 | 815 | |
|---|
| 768 | 816 | /* register control here */ |
|---|
| .. | .. |
|---|
| 772 | 820 | dev_err(tplg->dev, "ASoC: failed to add %s\n", |
|---|
| 773 | 821 | be->hdr.name); |
|---|
| 774 | 822 | kfree(sbe); |
|---|
| 775 | | - continue; |
|---|
| 823 | + break; |
|---|
| 776 | 824 | } |
|---|
| 777 | 825 | |
|---|
| 778 | 826 | list_add(&sbe->dobj.list, &tplg->comp->dobj_list); |
|---|
| 779 | 827 | } |
|---|
| 780 | | - return 0; |
|---|
| 828 | + return err; |
|---|
| 781 | 829 | |
|---|
| 782 | 830 | } |
|---|
| 783 | 831 | |
|---|
| .. | .. |
|---|
| 787 | 835 | struct snd_soc_tplg_mixer_control *mc; |
|---|
| 788 | 836 | struct soc_mixer_control *sm; |
|---|
| 789 | 837 | struct snd_kcontrol_new kc; |
|---|
| 790 | | - int i, err; |
|---|
| 838 | + int i; |
|---|
| 839 | + int err = 0; |
|---|
| 791 | 840 | |
|---|
| 792 | 841 | if (soc_tplg_check_elem_count(tplg, |
|---|
| 793 | 842 | sizeof(struct snd_soc_tplg_mixer_control), |
|---|
| .. | .. |
|---|
| 810 | 859 | if (sm == NULL) |
|---|
| 811 | 860 | return -ENOMEM; |
|---|
| 812 | 861 | tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + |
|---|
| 813 | | - mc->priv.size); |
|---|
| 862 | + le32_to_cpu(mc->priv.size)); |
|---|
| 814 | 863 | |
|---|
| 815 | 864 | dev_dbg(tplg->dev, |
|---|
| 816 | 865 | "ASoC: adding mixer kcontrol %s with access 0x%x\n", |
|---|
| .. | .. |
|---|
| 820 | 869 | kc.name = mc->hdr.name; |
|---|
| 821 | 870 | kc.private_value = (long)sm; |
|---|
| 822 | 871 | kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
|---|
| 823 | | - kc.access = mc->hdr.access; |
|---|
| 872 | + kc.access = le32_to_cpu(mc->hdr.access); |
|---|
| 824 | 873 | |
|---|
| 825 | 874 | /* we only support FL/FR channel mapping atm */ |
|---|
| 826 | 875 | sm->reg = tplc_chan_get_reg(tplg, mc->channel, |
|---|
| .. | .. |
|---|
| 832 | 881 | sm->rshift = tplc_chan_get_shift(tplg, mc->channel, |
|---|
| 833 | 882 | SNDRV_CHMAP_FR); |
|---|
| 834 | 883 | |
|---|
| 835 | | - sm->max = mc->max; |
|---|
| 836 | | - sm->min = mc->min; |
|---|
| 837 | | - sm->invert = mc->invert; |
|---|
| 838 | | - sm->platform_max = mc->platform_max; |
|---|
| 884 | + sm->max = le32_to_cpu(mc->max); |
|---|
| 885 | + sm->min = le32_to_cpu(mc->min); |
|---|
| 886 | + sm->invert = le32_to_cpu(mc->invert); |
|---|
| 887 | + sm->platform_max = le32_to_cpu(mc->platform_max); |
|---|
| 839 | 888 | sm->dobj.index = tplg->index; |
|---|
| 840 | 889 | sm->dobj.ops = tplg->ops; |
|---|
| 841 | 890 | sm->dobj.type = SND_SOC_DOBJ_MIXER; |
|---|
| .. | .. |
|---|
| 846 | 895 | if (err) { |
|---|
| 847 | 896 | soc_control_err(tplg, &mc->hdr, mc->hdr.name); |
|---|
| 848 | 897 | kfree(sm); |
|---|
| 849 | | - continue; |
|---|
| 898 | + break; |
|---|
| 899 | + } |
|---|
| 900 | + |
|---|
| 901 | + /* create any TLV data */ |
|---|
| 902 | + err = soc_tplg_create_tlv(tplg, &kc, &mc->hdr); |
|---|
| 903 | + if (err < 0) { |
|---|
| 904 | + dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", |
|---|
| 905 | + mc->hdr.name); |
|---|
| 906 | + kfree(sm); |
|---|
| 907 | + break; |
|---|
| 850 | 908 | } |
|---|
| 851 | 909 | |
|---|
| 852 | 910 | /* pass control to driver for optional further init */ |
|---|
| .. | .. |
|---|
| 855 | 913 | if (err < 0) { |
|---|
| 856 | 914 | dev_err(tplg->dev, "ASoC: failed to init %s\n", |
|---|
| 857 | 915 | mc->hdr.name); |
|---|
| 916 | + soc_tplg_free_tlv(tplg, &kc); |
|---|
| 858 | 917 | kfree(sm); |
|---|
| 859 | | - continue; |
|---|
| 918 | + break; |
|---|
| 860 | 919 | } |
|---|
| 861 | | - |
|---|
| 862 | | - /* create any TLV data */ |
|---|
| 863 | | - soc_tplg_create_tlv(tplg, &kc, &mc->hdr); |
|---|
| 864 | 920 | |
|---|
| 865 | 921 | /* register control here */ |
|---|
| 866 | 922 | err = soc_tplg_add_kcontrol(tplg, &kc, |
|---|
| .. | .. |
|---|
| 870 | 926 | mc->hdr.name); |
|---|
| 871 | 927 | soc_tplg_free_tlv(tplg, &kc); |
|---|
| 872 | 928 | kfree(sm); |
|---|
| 873 | | - continue; |
|---|
| 929 | + break; |
|---|
| 874 | 930 | } |
|---|
| 875 | 931 | |
|---|
| 876 | 932 | list_add(&sm->dobj.list, &tplg->comp->dobj_list); |
|---|
| 877 | 933 | } |
|---|
| 878 | 934 | |
|---|
| 879 | | - return 0; |
|---|
| 935 | + return err; |
|---|
| 880 | 936 | } |
|---|
| 881 | 937 | |
|---|
| 882 | 938 | static int soc_tplg_denum_create_texts(struct soc_enum *se, |
|---|
| .. | .. |
|---|
| 885 | 941 | int i, ret; |
|---|
| 886 | 942 | |
|---|
| 887 | 943 | se->dobj.control.dtexts = |
|---|
| 888 | | - kcalloc(ec->items, sizeof(char *), GFP_KERNEL); |
|---|
| 944 | + kcalloc(le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL); |
|---|
| 889 | 945 | if (se->dobj.control.dtexts == NULL) |
|---|
| 890 | 946 | return -ENOMEM; |
|---|
| 891 | 947 | |
|---|
| 892 | | - for (i = 0; i < ec->items; i++) { |
|---|
| 948 | + for (i = 0; i < le32_to_cpu(ec->items); i++) { |
|---|
| 893 | 949 | |
|---|
| 894 | 950 | if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| 895 | 951 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { |
|---|
| .. | .. |
|---|
| 904 | 960 | } |
|---|
| 905 | 961 | } |
|---|
| 906 | 962 | |
|---|
| 963 | + se->items = le32_to_cpu(ec->items); |
|---|
| 907 | 964 | se->texts = (const char * const *)se->dobj.control.dtexts; |
|---|
| 908 | 965 | return 0; |
|---|
| 909 | 966 | |
|---|
| 910 | 967 | err: |
|---|
| 968 | + se->items = i; |
|---|
| 969 | + soc_tplg_denum_remove_texts(se); |
|---|
| 970 | + return ret; |
|---|
| 971 | +} |
|---|
| 972 | + |
|---|
| 973 | +static inline void soc_tplg_denum_remove_texts(struct soc_enum *se) |
|---|
| 974 | +{ |
|---|
| 975 | + int i = se->items; |
|---|
| 976 | + |
|---|
| 911 | 977 | for (--i; i >= 0; i--) |
|---|
| 912 | 978 | kfree(se->dobj.control.dtexts[i]); |
|---|
| 913 | 979 | kfree(se->dobj.control.dtexts); |
|---|
| 914 | | - return ret; |
|---|
| 915 | 980 | } |
|---|
| 916 | 981 | |
|---|
| 917 | 982 | static int soc_tplg_denum_create_values(struct soc_enum *se, |
|---|
| 918 | 983 | struct snd_soc_tplg_enum_control *ec) |
|---|
| 919 | 984 | { |
|---|
| 920 | | - if (ec->items > sizeof(*ec->values)) |
|---|
| 985 | + int i; |
|---|
| 986 | + |
|---|
| 987 | + if (le32_to_cpu(ec->items) > sizeof(*ec->values)) |
|---|
| 921 | 988 | return -EINVAL; |
|---|
| 922 | 989 | |
|---|
| 923 | | - se->dobj.control.dvalues = kmemdup(ec->values, |
|---|
| 924 | | - ec->items * sizeof(u32), |
|---|
| 990 | + se->dobj.control.dvalues = kzalloc(le32_to_cpu(ec->items) * |
|---|
| 991 | + sizeof(*se->dobj.control.dvalues), |
|---|
| 925 | 992 | GFP_KERNEL); |
|---|
| 926 | 993 | if (!se->dobj.control.dvalues) |
|---|
| 927 | 994 | return -ENOMEM; |
|---|
| 928 | 995 | |
|---|
| 996 | + /* convert from little-endian */ |
|---|
| 997 | + for (i = 0; i < le32_to_cpu(ec->items); i++) { |
|---|
| 998 | + se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]); |
|---|
| 999 | + } |
|---|
| 1000 | + |
|---|
| 929 | 1001 | return 0; |
|---|
| 1002 | +} |
|---|
| 1003 | + |
|---|
| 1004 | +static inline void soc_tplg_denum_remove_values(struct soc_enum *se) |
|---|
| 1005 | +{ |
|---|
| 1006 | + kfree(se->dobj.control.dvalues); |
|---|
| 930 | 1007 | } |
|---|
| 931 | 1008 | |
|---|
| 932 | 1009 | static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, |
|---|
| .. | .. |
|---|
| 935 | 1012 | struct snd_soc_tplg_enum_control *ec; |
|---|
| 936 | 1013 | struct soc_enum *se; |
|---|
| 937 | 1014 | struct snd_kcontrol_new kc; |
|---|
| 938 | | - int i, ret, err; |
|---|
| 1015 | + int i; |
|---|
| 1016 | + int err = 0; |
|---|
| 939 | 1017 | |
|---|
| 940 | 1018 | if (soc_tplg_check_elem_count(tplg, |
|---|
| 941 | 1019 | sizeof(struct snd_soc_tplg_enum_control), |
|---|
| .. | .. |
|---|
| 948 | 1026 | |
|---|
| 949 | 1027 | for (i = 0; i < count; i++) { |
|---|
| 950 | 1028 | ec = (struct snd_soc_tplg_enum_control *)tplg->pos; |
|---|
| 951 | | - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + |
|---|
| 952 | | - ec->priv.size); |
|---|
| 953 | 1029 | |
|---|
| 954 | 1030 | /* validate kcontrol */ |
|---|
| 955 | 1031 | if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| .. | .. |
|---|
| 960 | 1036 | if (se == NULL) |
|---|
| 961 | 1037 | return -ENOMEM; |
|---|
| 962 | 1038 | |
|---|
| 1039 | + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + |
|---|
| 1040 | + le32_to_cpu(ec->priv.size)); |
|---|
| 1041 | + |
|---|
| 963 | 1042 | dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", |
|---|
| 964 | 1043 | ec->hdr.name, ec->items); |
|---|
| 965 | 1044 | |
|---|
| .. | .. |
|---|
| 967 | 1046 | kc.name = ec->hdr.name; |
|---|
| 968 | 1047 | kc.private_value = (long)se; |
|---|
| 969 | 1048 | kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
|---|
| 970 | | - kc.access = ec->hdr.access; |
|---|
| 1049 | + kc.access = le32_to_cpu(ec->hdr.access); |
|---|
| 971 | 1050 | |
|---|
| 972 | 1051 | se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); |
|---|
| 973 | 1052 | se->shift_l = tplc_chan_get_shift(tplg, ec->channel, |
|---|
| .. | .. |
|---|
| 975 | 1054 | se->shift_r = tplc_chan_get_shift(tplg, ec->channel, |
|---|
| 976 | 1055 | SNDRV_CHMAP_FL); |
|---|
| 977 | 1056 | |
|---|
| 978 | | - se->items = ec->items; |
|---|
| 979 | | - se->mask = ec->mask; |
|---|
| 1057 | + se->mask = le32_to_cpu(ec->mask); |
|---|
| 980 | 1058 | se->dobj.index = tplg->index; |
|---|
| 981 | 1059 | se->dobj.type = SND_SOC_DOBJ_ENUM; |
|---|
| 982 | 1060 | se->dobj.ops = tplg->ops; |
|---|
| 983 | 1061 | INIT_LIST_HEAD(&se->dobj.list); |
|---|
| 984 | 1062 | |
|---|
| 985 | | - switch (ec->hdr.ops.info) { |
|---|
| 1063 | + switch (le32_to_cpu(ec->hdr.ops.info)) { |
|---|
| 986 | 1064 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: |
|---|
| 987 | 1065 | case SND_SOC_TPLG_CTL_ENUM_VALUE: |
|---|
| 988 | 1066 | err = soc_tplg_denum_create_values(se, ec); |
|---|
| .. | .. |
|---|
| 990 | 1068 | dev_err(tplg->dev, |
|---|
| 991 | 1069 | "ASoC: could not create values for %s\n", |
|---|
| 992 | 1070 | ec->hdr.name); |
|---|
| 993 | | - kfree(se); |
|---|
| 994 | | - continue; |
|---|
| 1071 | + goto err_denum; |
|---|
| 995 | 1072 | } |
|---|
| 996 | | - /* fall through and create texts */ |
|---|
| 1073 | + fallthrough; |
|---|
| 997 | 1074 | case SND_SOC_TPLG_CTL_ENUM: |
|---|
| 998 | 1075 | case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: |
|---|
| 999 | 1076 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: |
|---|
| .. | .. |
|---|
| 1002 | 1079 | dev_err(tplg->dev, |
|---|
| 1003 | 1080 | "ASoC: could not create texts for %s\n", |
|---|
| 1004 | 1081 | ec->hdr.name); |
|---|
| 1005 | | - kfree(se); |
|---|
| 1006 | | - continue; |
|---|
| 1082 | + goto err_denum; |
|---|
| 1007 | 1083 | } |
|---|
| 1008 | 1084 | break; |
|---|
| 1009 | 1085 | default: |
|---|
| 1086 | + err = -EINVAL; |
|---|
| 1010 | 1087 | dev_err(tplg->dev, |
|---|
| 1011 | 1088 | "ASoC: invalid enum control type %d for %s\n", |
|---|
| 1012 | 1089 | ec->hdr.ops.info, ec->hdr.name); |
|---|
| 1013 | | - kfree(se); |
|---|
| 1014 | | - continue; |
|---|
| 1090 | + goto err_denum; |
|---|
| 1015 | 1091 | } |
|---|
| 1016 | 1092 | |
|---|
| 1017 | 1093 | /* map io handlers */ |
|---|
| 1018 | 1094 | err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg); |
|---|
| 1019 | 1095 | if (err) { |
|---|
| 1020 | 1096 | soc_control_err(tplg, &ec->hdr, ec->hdr.name); |
|---|
| 1021 | | - kfree(se); |
|---|
| 1022 | | - continue; |
|---|
| 1097 | + goto err_denum; |
|---|
| 1023 | 1098 | } |
|---|
| 1024 | 1099 | |
|---|
| 1025 | 1100 | /* pass control to driver for optional further init */ |
|---|
| .. | .. |
|---|
| 1028 | 1103 | if (err < 0) { |
|---|
| 1029 | 1104 | dev_err(tplg->dev, "ASoC: failed to init %s\n", |
|---|
| 1030 | 1105 | ec->hdr.name); |
|---|
| 1031 | | - kfree(se); |
|---|
| 1032 | | - continue; |
|---|
| 1106 | + goto err_denum; |
|---|
| 1033 | 1107 | } |
|---|
| 1034 | 1108 | |
|---|
| 1035 | 1109 | /* register control here */ |
|---|
| 1036 | | - ret = soc_tplg_add_kcontrol(tplg, |
|---|
| 1037 | | - &kc, &se->dobj.control.kcontrol); |
|---|
| 1038 | | - if (ret < 0) { |
|---|
| 1110 | + err = soc_tplg_add_kcontrol(tplg, |
|---|
| 1111 | + &kc, &se->dobj.control.kcontrol); |
|---|
| 1112 | + if (err < 0) { |
|---|
| 1039 | 1113 | dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n", |
|---|
| 1040 | 1114 | ec->hdr.name); |
|---|
| 1041 | | - kfree(se); |
|---|
| 1042 | | - continue; |
|---|
| 1115 | + goto err_denum; |
|---|
| 1043 | 1116 | } |
|---|
| 1044 | 1117 | |
|---|
| 1045 | 1118 | list_add(&se->dobj.list, &tplg->comp->dobj_list); |
|---|
| 1046 | 1119 | } |
|---|
| 1047 | | - |
|---|
| 1048 | 1120 | return 0; |
|---|
| 1121 | + |
|---|
| 1122 | +err_denum: |
|---|
| 1123 | + kfree(se); |
|---|
| 1124 | + return err; |
|---|
| 1049 | 1125 | } |
|---|
| 1050 | 1126 | |
|---|
| 1051 | 1127 | static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, |
|---|
| 1052 | 1128 | struct snd_soc_tplg_hdr *hdr) |
|---|
| 1053 | 1129 | { |
|---|
| 1054 | 1130 | struct snd_soc_tplg_ctl_hdr *control_hdr; |
|---|
| 1131 | + int ret; |
|---|
| 1055 | 1132 | int i; |
|---|
| 1056 | | - |
|---|
| 1057 | | - if (tplg->pass != SOC_TPLG_PASS_MIXER) { |
|---|
| 1058 | | - tplg->pos += hdr->size + hdr->payload_size; |
|---|
| 1059 | | - return 0; |
|---|
| 1060 | | - } |
|---|
| 1061 | 1133 | |
|---|
| 1062 | 1134 | dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count, |
|---|
| 1063 | 1135 | soc_tplg_get_offset(tplg)); |
|---|
| 1064 | 1136 | |
|---|
| 1065 | | - for (i = 0; i < hdr->count; i++) { |
|---|
| 1137 | + for (i = 0; i < le32_to_cpu(hdr->count); i++) { |
|---|
| 1066 | 1138 | |
|---|
| 1067 | 1139 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; |
|---|
| 1068 | 1140 | |
|---|
| 1069 | | - if (control_hdr->size != sizeof(*control_hdr)) { |
|---|
| 1141 | + if (le32_to_cpu(control_hdr->size) != sizeof(*control_hdr)) { |
|---|
| 1070 | 1142 | dev_err(tplg->dev, "ASoC: invalid control size\n"); |
|---|
| 1071 | 1143 | return -EINVAL; |
|---|
| 1072 | 1144 | } |
|---|
| 1073 | 1145 | |
|---|
| 1074 | | - switch (control_hdr->ops.info) { |
|---|
| 1146 | + switch (le32_to_cpu(control_hdr->ops.info)) { |
|---|
| 1075 | 1147 | case SND_SOC_TPLG_CTL_VOLSW: |
|---|
| 1076 | 1148 | case SND_SOC_TPLG_CTL_STROBE: |
|---|
| 1077 | 1149 | case SND_SOC_TPLG_CTL_VOLSW_SX: |
|---|
| .. | .. |
|---|
| 1079 | 1151 | case SND_SOC_TPLG_CTL_RANGE: |
|---|
| 1080 | 1152 | case SND_SOC_TPLG_DAPM_CTL_VOLSW: |
|---|
| 1081 | 1153 | case SND_SOC_TPLG_DAPM_CTL_PIN: |
|---|
| 1082 | | - soc_tplg_dmixer_create(tplg, 1, hdr->payload_size); |
|---|
| 1154 | + ret = soc_tplg_dmixer_create(tplg, 1, |
|---|
| 1155 | + le32_to_cpu(hdr->payload_size)); |
|---|
| 1083 | 1156 | break; |
|---|
| 1084 | 1157 | case SND_SOC_TPLG_CTL_ENUM: |
|---|
| 1085 | 1158 | case SND_SOC_TPLG_CTL_ENUM_VALUE: |
|---|
| 1086 | 1159 | case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: |
|---|
| 1087 | 1160 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: |
|---|
| 1088 | 1161 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: |
|---|
| 1089 | | - soc_tplg_denum_create(tplg, 1, hdr->payload_size); |
|---|
| 1162 | + ret = soc_tplg_denum_create(tplg, 1, |
|---|
| 1163 | + le32_to_cpu(hdr->payload_size)); |
|---|
| 1090 | 1164 | break; |
|---|
| 1091 | 1165 | case SND_SOC_TPLG_CTL_BYTES: |
|---|
| 1092 | | - soc_tplg_dbytes_create(tplg, 1, hdr->payload_size); |
|---|
| 1166 | + ret = soc_tplg_dbytes_create(tplg, 1, |
|---|
| 1167 | + le32_to_cpu(hdr->payload_size)); |
|---|
| 1093 | 1168 | break; |
|---|
| 1094 | 1169 | default: |
|---|
| 1095 | 1170 | soc_bind_err(tplg, control_hdr, i); |
|---|
| 1096 | 1171 | return -EINVAL; |
|---|
| 1097 | 1172 | } |
|---|
| 1173 | + if (ret < 0) { |
|---|
| 1174 | + dev_err(tplg->dev, "ASoC: invalid control\n"); |
|---|
| 1175 | + return ret; |
|---|
| 1176 | + } |
|---|
| 1177 | + |
|---|
| 1098 | 1178 | } |
|---|
| 1099 | 1179 | |
|---|
| 1100 | 1180 | return 0; |
|---|
| .. | .. |
|---|
| 1104 | 1184 | static int soc_tplg_add_route(struct soc_tplg *tplg, |
|---|
| 1105 | 1185 | struct snd_soc_dapm_route *route) |
|---|
| 1106 | 1186 | { |
|---|
| 1107 | | - if (tplg->comp && tplg->ops && tplg->ops->dapm_route_load) |
|---|
| 1187 | + if (tplg->ops && tplg->ops->dapm_route_load) |
|---|
| 1108 | 1188 | return tplg->ops->dapm_route_load(tplg->comp, tplg->index, |
|---|
| 1109 | 1189 | route); |
|---|
| 1110 | 1190 | |
|---|
| .. | .. |
|---|
| 1115 | 1195 | struct snd_soc_tplg_hdr *hdr) |
|---|
| 1116 | 1196 | { |
|---|
| 1117 | 1197 | struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; |
|---|
| 1118 | | - struct snd_soc_dapm_route route; |
|---|
| 1119 | 1198 | struct snd_soc_tplg_dapm_graph_elem *elem; |
|---|
| 1120 | | - int count = hdr->count, i; |
|---|
| 1199 | + struct snd_soc_dapm_route **routes; |
|---|
| 1200 | + int count, i, j; |
|---|
| 1201 | + int ret = 0; |
|---|
| 1121 | 1202 | |
|---|
| 1122 | | - if (tplg->pass != SOC_TPLG_PASS_GRAPH) { |
|---|
| 1123 | | - tplg->pos += hdr->size + hdr->payload_size; |
|---|
| 1124 | | - return 0; |
|---|
| 1125 | | - } |
|---|
| 1203 | + count = le32_to_cpu(hdr->count); |
|---|
| 1126 | 1204 | |
|---|
| 1127 | 1205 | if (soc_tplg_check_elem_count(tplg, |
|---|
| 1128 | 1206 | sizeof(struct snd_soc_tplg_dapm_graph_elem), |
|---|
| 1129 | | - count, hdr->payload_size, "graph")) { |
|---|
| 1207 | + count, le32_to_cpu(hdr->payload_size), "graph")) { |
|---|
| 1130 | 1208 | |
|---|
| 1131 | 1209 | dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n", |
|---|
| 1132 | 1210 | count); |
|---|
| .. | .. |
|---|
| 1136 | 1214 | dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count, |
|---|
| 1137 | 1215 | hdr->index); |
|---|
| 1138 | 1216 | |
|---|
| 1217 | + /* allocate memory for pointer to array of dapm routes */ |
|---|
| 1218 | + routes = kcalloc(count, sizeof(struct snd_soc_dapm_route *), |
|---|
| 1219 | + GFP_KERNEL); |
|---|
| 1220 | + if (!routes) |
|---|
| 1221 | + return -ENOMEM; |
|---|
| 1222 | + |
|---|
| 1223 | + /* |
|---|
| 1224 | + * allocate memory for each dapm route in the array. |
|---|
| 1225 | + * This needs to be done individually so that |
|---|
| 1226 | + * each route can be freed when it is removed in remove_route(). |
|---|
| 1227 | + */ |
|---|
| 1228 | + for (i = 0; i < count; i++) { |
|---|
| 1229 | + routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL); |
|---|
| 1230 | + if (!routes[i]) { |
|---|
| 1231 | + /* free previously allocated memory */ |
|---|
| 1232 | + for (j = 0; j < i; j++) |
|---|
| 1233 | + kfree(routes[j]); |
|---|
| 1234 | + |
|---|
| 1235 | + kfree(routes); |
|---|
| 1236 | + return -ENOMEM; |
|---|
| 1237 | + } |
|---|
| 1238 | + } |
|---|
| 1239 | + |
|---|
| 1139 | 1240 | for (i = 0; i < count; i++) { |
|---|
| 1140 | 1241 | elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; |
|---|
| 1141 | 1242 | tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); |
|---|
| 1142 | 1243 | |
|---|
| 1143 | 1244 | /* validate routes */ |
|---|
| 1144 | 1245 | if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| 1145 | | - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) |
|---|
| 1146 | | - return -EINVAL; |
|---|
| 1246 | + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { |
|---|
| 1247 | + ret = -EINVAL; |
|---|
| 1248 | + break; |
|---|
| 1249 | + } |
|---|
| 1147 | 1250 | if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| 1148 | | - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) |
|---|
| 1149 | | - return -EINVAL; |
|---|
| 1251 | + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { |
|---|
| 1252 | + ret = -EINVAL; |
|---|
| 1253 | + break; |
|---|
| 1254 | + } |
|---|
| 1150 | 1255 | if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| 1151 | | - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) |
|---|
| 1152 | | - return -EINVAL; |
|---|
| 1256 | + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { |
|---|
| 1257 | + ret = -EINVAL; |
|---|
| 1258 | + break; |
|---|
| 1259 | + } |
|---|
| 1153 | 1260 | |
|---|
| 1154 | | - route.source = elem->source; |
|---|
| 1155 | | - route.sink = elem->sink; |
|---|
| 1156 | | - route.connected = NULL; /* set to NULL atm for tplg users */ |
|---|
| 1261 | + routes[i]->source = elem->source; |
|---|
| 1262 | + routes[i]->sink = elem->sink; |
|---|
| 1263 | + |
|---|
| 1264 | + /* set to NULL atm for tplg users */ |
|---|
| 1265 | + routes[i]->connected = NULL; |
|---|
| 1157 | 1266 | if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) |
|---|
| 1158 | | - route.control = NULL; |
|---|
| 1267 | + routes[i]->control = NULL; |
|---|
| 1159 | 1268 | else |
|---|
| 1160 | | - route.control = elem->control; |
|---|
| 1269 | + routes[i]->control = elem->control; |
|---|
| 1161 | 1270 | |
|---|
| 1162 | | - soc_tplg_add_route(tplg, &route); |
|---|
| 1271 | + /* add route dobj to dobj_list */ |
|---|
| 1272 | + routes[i]->dobj.type = SND_SOC_DOBJ_GRAPH; |
|---|
| 1273 | + routes[i]->dobj.ops = tplg->ops; |
|---|
| 1274 | + routes[i]->dobj.index = tplg->index; |
|---|
| 1275 | + list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list); |
|---|
| 1276 | + |
|---|
| 1277 | + ret = soc_tplg_add_route(tplg, routes[i]); |
|---|
| 1278 | + if (ret < 0) { |
|---|
| 1279 | + dev_err(tplg->dev, "ASoC: topology: add_route failed: %d\n", ret); |
|---|
| 1280 | + /* |
|---|
| 1281 | + * this route was added to the list, it will |
|---|
| 1282 | + * be freed in remove_route() so increment the |
|---|
| 1283 | + * counter to skip it in the error handling |
|---|
| 1284 | + * below. |
|---|
| 1285 | + */ |
|---|
| 1286 | + i++; |
|---|
| 1287 | + break; |
|---|
| 1288 | + } |
|---|
| 1163 | 1289 | |
|---|
| 1164 | 1290 | /* add route, but keep going if some fail */ |
|---|
| 1165 | | - snd_soc_dapm_add_routes(dapm, &route, 1); |
|---|
| 1291 | + snd_soc_dapm_add_routes(dapm, routes[i], 1); |
|---|
| 1166 | 1292 | } |
|---|
| 1167 | 1293 | |
|---|
| 1168 | | - return 0; |
|---|
| 1294 | + /* |
|---|
| 1295 | + * free memory allocated for all dapm routes not added to the |
|---|
| 1296 | + * list in case of error |
|---|
| 1297 | + */ |
|---|
| 1298 | + if (ret < 0) { |
|---|
| 1299 | + while (i < count) |
|---|
| 1300 | + kfree(routes[i++]); |
|---|
| 1301 | + } |
|---|
| 1302 | + |
|---|
| 1303 | + /* |
|---|
| 1304 | + * free pointer to array of dapm routes as this is no longer needed. |
|---|
| 1305 | + * The memory allocated for each dapm route will be freed |
|---|
| 1306 | + * when it is removed in remove_route(). |
|---|
| 1307 | + */ |
|---|
| 1308 | + kfree(routes); |
|---|
| 1309 | + |
|---|
| 1310 | + return ret; |
|---|
| 1169 | 1311 | } |
|---|
| 1170 | 1312 | |
|---|
| 1171 | 1313 | static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( |
|---|
| .. | .. |
|---|
| 1182 | 1324 | |
|---|
| 1183 | 1325 | for (i = 0; i < num_kcontrols; i++) { |
|---|
| 1184 | 1326 | mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; |
|---|
| 1185 | | - sm = kzalloc(sizeof(*sm), GFP_KERNEL); |
|---|
| 1186 | | - if (sm == NULL) |
|---|
| 1187 | | - goto err; |
|---|
| 1188 | | - |
|---|
| 1189 | | - tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + |
|---|
| 1190 | | - mc->priv.size); |
|---|
| 1191 | 1327 | |
|---|
| 1192 | 1328 | /* validate kcontrol */ |
|---|
| 1193 | 1329 | if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| 1194 | 1330 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) |
|---|
| 1195 | | - goto err_str; |
|---|
| 1331 | + goto err_sm; |
|---|
| 1332 | + |
|---|
| 1333 | + sm = kzalloc(sizeof(*sm), GFP_KERNEL); |
|---|
| 1334 | + if (sm == NULL) |
|---|
| 1335 | + goto err_sm; |
|---|
| 1336 | + |
|---|
| 1337 | + tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + |
|---|
| 1338 | + le32_to_cpu(mc->priv.size)); |
|---|
| 1196 | 1339 | |
|---|
| 1197 | 1340 | dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", |
|---|
| 1198 | 1341 | mc->hdr.name, i); |
|---|
| 1199 | 1342 | |
|---|
| 1343 | + kc[i].private_value = (long)sm; |
|---|
| 1200 | 1344 | kc[i].name = kstrdup(mc->hdr.name, GFP_KERNEL); |
|---|
| 1201 | 1345 | if (kc[i].name == NULL) |
|---|
| 1202 | | - goto err_str; |
|---|
| 1203 | | - kc[i].private_value = (long)sm; |
|---|
| 1346 | + goto err_sm; |
|---|
| 1204 | 1347 | kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
|---|
| 1205 | | - kc[i].access = mc->hdr.access; |
|---|
| 1348 | + kc[i].access = le32_to_cpu(mc->hdr.access); |
|---|
| 1206 | 1349 | |
|---|
| 1207 | 1350 | /* we only support FL/FR channel mapping atm */ |
|---|
| 1208 | 1351 | sm->reg = tplc_chan_get_reg(tplg, mc->channel, |
|---|
| .. | .. |
|---|
| 1214 | 1357 | sm->rshift = tplc_chan_get_shift(tplg, mc->channel, |
|---|
| 1215 | 1358 | SNDRV_CHMAP_FR); |
|---|
| 1216 | 1359 | |
|---|
| 1217 | | - sm->max = mc->max; |
|---|
| 1218 | | - sm->min = mc->min; |
|---|
| 1219 | | - sm->invert = mc->invert; |
|---|
| 1220 | | - sm->platform_max = mc->platform_max; |
|---|
| 1360 | + sm->max = le32_to_cpu(mc->max); |
|---|
| 1361 | + sm->min = le32_to_cpu(mc->min); |
|---|
| 1362 | + sm->invert = le32_to_cpu(mc->invert); |
|---|
| 1363 | + sm->platform_max = le32_to_cpu(mc->platform_max); |
|---|
| 1221 | 1364 | sm->dobj.index = tplg->index; |
|---|
| 1222 | 1365 | INIT_LIST_HEAD(&sm->dobj.list); |
|---|
| 1223 | 1366 | |
|---|
| .. | .. |
|---|
| 1225 | 1368 | err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], tplg); |
|---|
| 1226 | 1369 | if (err) { |
|---|
| 1227 | 1370 | soc_control_err(tplg, &mc->hdr, mc->hdr.name); |
|---|
| 1228 | | - kfree(sm); |
|---|
| 1229 | | - continue; |
|---|
| 1371 | + goto err_sm; |
|---|
| 1372 | + } |
|---|
| 1373 | + |
|---|
| 1374 | + /* create any TLV data */ |
|---|
| 1375 | + err = soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); |
|---|
| 1376 | + if (err < 0) { |
|---|
| 1377 | + dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", |
|---|
| 1378 | + mc->hdr.name); |
|---|
| 1379 | + goto err_sm; |
|---|
| 1230 | 1380 | } |
|---|
| 1231 | 1381 | |
|---|
| 1232 | 1382 | /* pass control to driver for optional further init */ |
|---|
| .. | .. |
|---|
| 1235 | 1385 | if (err < 0) { |
|---|
| 1236 | 1386 | dev_err(tplg->dev, "ASoC: failed to init %s\n", |
|---|
| 1237 | 1387 | mc->hdr.name); |
|---|
| 1238 | | - kfree(sm); |
|---|
| 1239 | | - continue; |
|---|
| 1388 | + goto err_sm; |
|---|
| 1240 | 1389 | } |
|---|
| 1241 | | - |
|---|
| 1242 | | - /* create any TLV data */ |
|---|
| 1243 | | - soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); |
|---|
| 1244 | 1390 | } |
|---|
| 1245 | 1391 | return kc; |
|---|
| 1246 | 1392 | |
|---|
| 1247 | | -err_str: |
|---|
| 1248 | | - kfree(sm); |
|---|
| 1249 | | -err: |
|---|
| 1250 | | - for (--i; i >= 0; i--) { |
|---|
| 1251 | | - kfree((void *)kc[i].private_value); |
|---|
| 1393 | +err_sm: |
|---|
| 1394 | + for (; i >= 0; i--) { |
|---|
| 1395 | + soc_tplg_free_tlv(tplg, &kc[i]); |
|---|
| 1396 | + sm = (struct soc_mixer_control *)kc[i].private_value; |
|---|
| 1397 | + kfree(sm); |
|---|
| 1252 | 1398 | kfree(kc[i].name); |
|---|
| 1253 | 1399 | } |
|---|
| 1254 | 1400 | kfree(kc); |
|---|
| 1401 | + |
|---|
| 1255 | 1402 | return NULL; |
|---|
| 1256 | 1403 | } |
|---|
| 1257 | 1404 | |
|---|
| .. | .. |
|---|
| 1261 | 1408 | struct snd_kcontrol_new *kc; |
|---|
| 1262 | 1409 | struct snd_soc_tplg_enum_control *ec; |
|---|
| 1263 | 1410 | struct soc_enum *se; |
|---|
| 1264 | | - int i, j, err; |
|---|
| 1411 | + int i, err; |
|---|
| 1265 | 1412 | |
|---|
| 1266 | 1413 | kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); |
|---|
| 1267 | 1414 | if (kc == NULL) |
|---|
| .. | .. |
|---|
| 1272 | 1419 | /* validate kcontrol */ |
|---|
| 1273 | 1420 | if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| 1274 | 1421 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) |
|---|
| 1275 | | - goto err; |
|---|
| 1422 | + goto err_se; |
|---|
| 1276 | 1423 | |
|---|
| 1277 | 1424 | se = kzalloc(sizeof(*se), GFP_KERNEL); |
|---|
| 1278 | 1425 | if (se == NULL) |
|---|
| 1279 | | - goto err; |
|---|
| 1426 | + goto err_se; |
|---|
| 1427 | + |
|---|
| 1428 | + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + |
|---|
| 1429 | + le32_to_cpu(ec->priv.size)); |
|---|
| 1280 | 1430 | |
|---|
| 1281 | 1431 | dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", |
|---|
| 1282 | 1432 | ec->hdr.name); |
|---|
| 1283 | 1433 | |
|---|
| 1284 | | - kc[i].name = kstrdup(ec->hdr.name, GFP_KERNEL); |
|---|
| 1285 | | - if (kc[i].name == NULL) { |
|---|
| 1286 | | - kfree(se); |
|---|
| 1287 | | - goto err_se; |
|---|
| 1288 | | - } |
|---|
| 1289 | 1434 | kc[i].private_value = (long)se; |
|---|
| 1435 | + kc[i].name = kstrdup(ec->hdr.name, GFP_KERNEL); |
|---|
| 1436 | + if (kc[i].name == NULL) |
|---|
| 1437 | + goto err_se; |
|---|
| 1290 | 1438 | kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
|---|
| 1291 | | - kc[i].access = ec->hdr.access; |
|---|
| 1439 | + kc[i].access = le32_to_cpu(ec->hdr.access); |
|---|
| 1292 | 1440 | |
|---|
| 1293 | 1441 | /* we only support FL/FR channel mapping atm */ |
|---|
| 1294 | 1442 | se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); |
|---|
| .. | .. |
|---|
| 1297 | 1445 | se->shift_r = tplc_chan_get_shift(tplg, ec->channel, |
|---|
| 1298 | 1446 | SNDRV_CHMAP_FR); |
|---|
| 1299 | 1447 | |
|---|
| 1300 | | - se->items = ec->items; |
|---|
| 1301 | | - se->mask = ec->mask; |
|---|
| 1448 | + se->items = le32_to_cpu(ec->items); |
|---|
| 1449 | + se->mask = le32_to_cpu(ec->mask); |
|---|
| 1302 | 1450 | se->dobj.index = tplg->index; |
|---|
| 1303 | 1451 | |
|---|
| 1304 | | - switch (ec->hdr.ops.info) { |
|---|
| 1452 | + switch (le32_to_cpu(ec->hdr.ops.info)) { |
|---|
| 1305 | 1453 | case SND_SOC_TPLG_CTL_ENUM_VALUE: |
|---|
| 1306 | 1454 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: |
|---|
| 1307 | 1455 | err = soc_tplg_denum_create_values(se, ec); |
|---|
| .. | .. |
|---|
| 1310 | 1458 | ec->hdr.name); |
|---|
| 1311 | 1459 | goto err_se; |
|---|
| 1312 | 1460 | } |
|---|
| 1313 | | - /* fall through to create texts */ |
|---|
| 1461 | + fallthrough; |
|---|
| 1314 | 1462 | case SND_SOC_TPLG_CTL_ENUM: |
|---|
| 1315 | 1463 | case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: |
|---|
| 1316 | 1464 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: |
|---|
| .. | .. |
|---|
| 1342 | 1490 | ec->hdr.name); |
|---|
| 1343 | 1491 | goto err_se; |
|---|
| 1344 | 1492 | } |
|---|
| 1345 | | - |
|---|
| 1346 | | - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + |
|---|
| 1347 | | - ec->priv.size); |
|---|
| 1348 | 1493 | } |
|---|
| 1349 | 1494 | |
|---|
| 1350 | 1495 | return kc; |
|---|
| .. | .. |
|---|
| 1353 | 1498 | for (; i >= 0; i--) { |
|---|
| 1354 | 1499 | /* free values and texts */ |
|---|
| 1355 | 1500 | se = (struct soc_enum *)kc[i].private_value; |
|---|
| 1356 | | - if (!se) |
|---|
| 1357 | | - continue; |
|---|
| 1358 | 1501 | |
|---|
| 1359 | | - kfree(se->dobj.control.dvalues); |
|---|
| 1360 | | - for (j = 0; j < ec->items; j++) |
|---|
| 1361 | | - kfree(se->dobj.control.dtexts[j]); |
|---|
| 1502 | + if (se) { |
|---|
| 1503 | + soc_tplg_denum_remove_values(se); |
|---|
| 1504 | + soc_tplg_denum_remove_texts(se); |
|---|
| 1505 | + } |
|---|
| 1362 | 1506 | |
|---|
| 1363 | 1507 | kfree(se); |
|---|
| 1364 | 1508 | kfree(kc[i].name); |
|---|
| 1365 | 1509 | } |
|---|
| 1366 | | -err: |
|---|
| 1367 | 1510 | kfree(kc); |
|---|
| 1368 | 1511 | |
|---|
| 1369 | 1512 | return NULL; |
|---|
| 1370 | 1513 | } |
|---|
| 1371 | 1514 | |
|---|
| 1372 | 1515 | static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( |
|---|
| 1373 | | - struct soc_tplg *tplg, int count) |
|---|
| 1516 | + struct soc_tplg *tplg, int num_kcontrols) |
|---|
| 1374 | 1517 | { |
|---|
| 1375 | 1518 | struct snd_soc_tplg_bytes_control *be; |
|---|
| 1376 | | - struct soc_bytes_ext *sbe; |
|---|
| 1519 | + struct soc_bytes_ext *sbe; |
|---|
| 1377 | 1520 | struct snd_kcontrol_new *kc; |
|---|
| 1378 | 1521 | int i, err; |
|---|
| 1379 | 1522 | |
|---|
| 1380 | | - kc = kcalloc(count, sizeof(*kc), GFP_KERNEL); |
|---|
| 1523 | + kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); |
|---|
| 1381 | 1524 | if (!kc) |
|---|
| 1382 | 1525 | return NULL; |
|---|
| 1383 | 1526 | |
|---|
| 1384 | | - for (i = 0; i < count; i++) { |
|---|
| 1527 | + for (i = 0; i < num_kcontrols; i++) { |
|---|
| 1385 | 1528 | be = (struct snd_soc_tplg_bytes_control *)tplg->pos; |
|---|
| 1386 | 1529 | |
|---|
| 1387 | 1530 | /* validate kcontrol */ |
|---|
| 1388 | 1531 | if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == |
|---|
| 1389 | 1532 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) |
|---|
| 1390 | | - goto err; |
|---|
| 1533 | + goto err_sbe; |
|---|
| 1391 | 1534 | |
|---|
| 1392 | 1535 | sbe = kzalloc(sizeof(*sbe), GFP_KERNEL); |
|---|
| 1393 | 1536 | if (sbe == NULL) |
|---|
| 1394 | | - goto err; |
|---|
| 1537 | + goto err_sbe; |
|---|
| 1395 | 1538 | |
|---|
| 1396 | 1539 | tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + |
|---|
| 1397 | | - be->priv.size); |
|---|
| 1540 | + le32_to_cpu(be->priv.size)); |
|---|
| 1398 | 1541 | |
|---|
| 1399 | 1542 | dev_dbg(tplg->dev, |
|---|
| 1400 | 1543 | "ASoC: adding bytes kcontrol %s with access 0x%x\n", |
|---|
| 1401 | 1544 | be->hdr.name, be->hdr.access); |
|---|
| 1402 | 1545 | |
|---|
| 1403 | | - kc[i].name = kstrdup(be->hdr.name, GFP_KERNEL); |
|---|
| 1404 | | - if (kc[i].name == NULL) { |
|---|
| 1405 | | - kfree(sbe); |
|---|
| 1406 | | - goto err; |
|---|
| 1407 | | - } |
|---|
| 1408 | 1546 | kc[i].private_value = (long)sbe; |
|---|
| 1547 | + kc[i].name = kstrdup(be->hdr.name, GFP_KERNEL); |
|---|
| 1548 | + if (kc[i].name == NULL) |
|---|
| 1549 | + goto err_sbe; |
|---|
| 1409 | 1550 | kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
|---|
| 1410 | | - kc[i].access = be->hdr.access; |
|---|
| 1551 | + kc[i].access = le32_to_cpu(be->hdr.access); |
|---|
| 1411 | 1552 | |
|---|
| 1412 | | - sbe->max = be->max; |
|---|
| 1553 | + sbe->max = le32_to_cpu(be->max); |
|---|
| 1413 | 1554 | INIT_LIST_HEAD(&sbe->dobj.list); |
|---|
| 1414 | 1555 | |
|---|
| 1415 | 1556 | /* map standard io handlers and check for external handlers */ |
|---|
| 1416 | 1557 | err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], tplg); |
|---|
| 1417 | 1558 | if (err) { |
|---|
| 1418 | 1559 | soc_control_err(tplg, &be->hdr, be->hdr.name); |
|---|
| 1419 | | - kfree(sbe); |
|---|
| 1420 | | - continue; |
|---|
| 1560 | + goto err_sbe; |
|---|
| 1421 | 1561 | } |
|---|
| 1422 | 1562 | |
|---|
| 1423 | 1563 | /* pass control to driver for optional further init */ |
|---|
| .. | .. |
|---|
| 1426 | 1566 | if (err < 0) { |
|---|
| 1427 | 1567 | dev_err(tplg->dev, "ASoC: failed to init %s\n", |
|---|
| 1428 | 1568 | be->hdr.name); |
|---|
| 1429 | | - kfree(sbe); |
|---|
| 1430 | | - continue; |
|---|
| 1569 | + goto err_sbe; |
|---|
| 1431 | 1570 | } |
|---|
| 1432 | 1571 | } |
|---|
| 1433 | 1572 | |
|---|
| 1434 | 1573 | return kc; |
|---|
| 1435 | 1574 | |
|---|
| 1436 | | -err: |
|---|
| 1437 | | - for (--i; i >= 0; i--) { |
|---|
| 1438 | | - kfree((void *)kc[i].private_value); |
|---|
| 1575 | +err_sbe: |
|---|
| 1576 | + for (; i >= 0; i--) { |
|---|
| 1577 | + sbe = (struct soc_bytes_ext *)kc[i].private_value; |
|---|
| 1578 | + kfree(sbe); |
|---|
| 1439 | 1579 | kfree(kc[i].name); |
|---|
| 1440 | 1580 | } |
|---|
| 1441 | | - |
|---|
| 1442 | 1581 | kfree(kc); |
|---|
| 1582 | + |
|---|
| 1443 | 1583 | return NULL; |
|---|
| 1444 | 1584 | } |
|---|
| 1445 | 1585 | |
|---|
| .. | .. |
|---|
| 1466 | 1606 | memset(&template, 0, sizeof(template)); |
|---|
| 1467 | 1607 | |
|---|
| 1468 | 1608 | /* map user to kernel widget ID */ |
|---|
| 1469 | | - template.id = get_widget_id(w->id); |
|---|
| 1470 | | - if (template.id < 0) |
|---|
| 1609 | + template.id = get_widget_id(le32_to_cpu(w->id)); |
|---|
| 1610 | + if ((int)template.id < 0) |
|---|
| 1471 | 1611 | return template.id; |
|---|
| 1472 | 1612 | |
|---|
| 1473 | 1613 | /* strings are allocated here, but used and freed by the widget */ |
|---|
| .. | .. |
|---|
| 1479 | 1619 | ret = -ENOMEM; |
|---|
| 1480 | 1620 | goto err; |
|---|
| 1481 | 1621 | } |
|---|
| 1482 | | - template.reg = w->reg; |
|---|
| 1483 | | - template.shift = w->shift; |
|---|
| 1484 | | - template.mask = w->mask; |
|---|
| 1485 | | - template.subseq = w->subseq; |
|---|
| 1622 | + template.reg = le32_to_cpu(w->reg); |
|---|
| 1623 | + template.shift = le32_to_cpu(w->shift); |
|---|
| 1624 | + template.mask = le32_to_cpu(w->mask); |
|---|
| 1625 | + template.subseq = le32_to_cpu(w->subseq); |
|---|
| 1486 | 1626 | template.on_val = w->invert ? 0 : 1; |
|---|
| 1487 | 1627 | template.off_val = w->invert ? 1 : 0; |
|---|
| 1488 | | - template.ignore_suspend = w->ignore_suspend; |
|---|
| 1489 | | - template.event_flags = w->event_flags; |
|---|
| 1628 | + template.ignore_suspend = le32_to_cpu(w->ignore_suspend); |
|---|
| 1629 | + template.event_flags = le16_to_cpu(w->event_flags); |
|---|
| 1490 | 1630 | template.dobj.index = tplg->index; |
|---|
| 1491 | 1631 | |
|---|
| 1492 | 1632 | tplg->pos += |
|---|
| 1493 | | - (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size); |
|---|
| 1633 | + (sizeof(struct snd_soc_tplg_dapm_widget) + |
|---|
| 1634 | + le32_to_cpu(w->priv.size)); |
|---|
| 1635 | + |
|---|
| 1494 | 1636 | if (w->num_kcontrols == 0) { |
|---|
| 1495 | 1637 | kcontrol_type = 0; |
|---|
| 1496 | 1638 | template.num_kcontrols = 0; |
|---|
| .. | .. |
|---|
| 1501 | 1643 | dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n", |
|---|
| 1502 | 1644 | w->name, w->num_kcontrols, control_hdr->type); |
|---|
| 1503 | 1645 | |
|---|
| 1504 | | - switch (control_hdr->ops.info) { |
|---|
| 1646 | + switch (le32_to_cpu(control_hdr->ops.info)) { |
|---|
| 1505 | 1647 | case SND_SOC_TPLG_CTL_VOLSW: |
|---|
| 1506 | 1648 | case SND_SOC_TPLG_CTL_STROBE: |
|---|
| 1507 | 1649 | case SND_SOC_TPLG_CTL_VOLSW_SX: |
|---|
| .. | .. |
|---|
| 1509 | 1651 | case SND_SOC_TPLG_CTL_RANGE: |
|---|
| 1510 | 1652 | case SND_SOC_TPLG_DAPM_CTL_VOLSW: |
|---|
| 1511 | 1653 | kcontrol_type = SND_SOC_TPLG_TYPE_MIXER; /* volume mixer */ |
|---|
| 1512 | | - template.num_kcontrols = w->num_kcontrols; |
|---|
| 1654 | + template.num_kcontrols = le32_to_cpu(w->num_kcontrols); |
|---|
| 1513 | 1655 | template.kcontrol_news = |
|---|
| 1514 | 1656 | soc_tplg_dapm_widget_dmixer_create(tplg, |
|---|
| 1515 | 1657 | template.num_kcontrols); |
|---|
| .. | .. |
|---|
| 1524 | 1666 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: |
|---|
| 1525 | 1667 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: |
|---|
| 1526 | 1668 | kcontrol_type = SND_SOC_TPLG_TYPE_ENUM; /* enumerated mixer */ |
|---|
| 1527 | | - template.num_kcontrols = w->num_kcontrols; |
|---|
| 1669 | + template.num_kcontrols = le32_to_cpu(w->num_kcontrols); |
|---|
| 1528 | 1670 | template.kcontrol_news = |
|---|
| 1529 | 1671 | soc_tplg_dapm_widget_denum_create(tplg, |
|---|
| 1530 | 1672 | template.num_kcontrols); |
|---|
| .. | .. |
|---|
| 1535 | 1677 | break; |
|---|
| 1536 | 1678 | case SND_SOC_TPLG_CTL_BYTES: |
|---|
| 1537 | 1679 | kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */ |
|---|
| 1538 | | - template.num_kcontrols = w->num_kcontrols; |
|---|
| 1680 | + template.num_kcontrols = le32_to_cpu(w->num_kcontrols); |
|---|
| 1539 | 1681 | template.kcontrol_news = |
|---|
| 1540 | 1682 | soc_tplg_dapm_widget_dbytes_create(tplg, |
|---|
| 1541 | 1683 | template.num_kcontrols); |
|---|
| .. | .. |
|---|
| 1547 | 1689 | default: |
|---|
| 1548 | 1690 | dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n", |
|---|
| 1549 | 1691 | control_hdr->ops.get, control_hdr->ops.put, |
|---|
| 1550 | | - control_hdr->ops.info); |
|---|
| 1692 | + le32_to_cpu(control_hdr->ops.info)); |
|---|
| 1551 | 1693 | ret = -EINVAL; |
|---|
| 1552 | 1694 | goto hdr_err; |
|---|
| 1553 | 1695 | } |
|---|
| .. | .. |
|---|
| 1565 | 1707 | widget = snd_soc_dapm_new_control_unlocked(dapm, &template); |
|---|
| 1566 | 1708 | if (IS_ERR(widget)) { |
|---|
| 1567 | 1709 | ret = PTR_ERR(widget); |
|---|
| 1568 | | - /* Do not nag about probe deferrals */ |
|---|
| 1569 | | - if (ret != -EPROBE_DEFER) |
|---|
| 1570 | | - dev_err(tplg->dev, |
|---|
| 1571 | | - "ASoC: failed to create widget %s controls (%d)\n", |
|---|
| 1572 | | - w->name, ret); |
|---|
| 1573 | | - goto hdr_err; |
|---|
| 1574 | | - } |
|---|
| 1575 | | - if (widget == NULL) { |
|---|
| 1576 | | - dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n", |
|---|
| 1577 | | - w->name); |
|---|
| 1578 | | - ret = -ENOMEM; |
|---|
| 1579 | 1710 | goto hdr_err; |
|---|
| 1580 | 1711 | } |
|---|
| 1581 | 1712 | |
|---|
| .. | .. |
|---|
| 1588 | 1719 | ret = soc_tplg_widget_ready(tplg, widget, w); |
|---|
| 1589 | 1720 | if (ret < 0) |
|---|
| 1590 | 1721 | goto ready_err; |
|---|
| 1722 | + |
|---|
| 1723 | + kfree(template.sname); |
|---|
| 1724 | + kfree(template.name); |
|---|
| 1591 | 1725 | |
|---|
| 1592 | 1726 | return 0; |
|---|
| 1593 | 1727 | |
|---|
| .. | .. |
|---|
| 1605 | 1739 | struct snd_soc_tplg_hdr *hdr) |
|---|
| 1606 | 1740 | { |
|---|
| 1607 | 1741 | struct snd_soc_tplg_dapm_widget *widget; |
|---|
| 1608 | | - int ret, count = hdr->count, i; |
|---|
| 1742 | + int ret, count, i; |
|---|
| 1609 | 1743 | |
|---|
| 1610 | | - if (tplg->pass != SOC_TPLG_PASS_WIDGET) |
|---|
| 1611 | | - return 0; |
|---|
| 1744 | + count = le32_to_cpu(hdr->count); |
|---|
| 1612 | 1745 | |
|---|
| 1613 | 1746 | dev_dbg(tplg->dev, "ASoC: adding %d DAPM widgets\n", count); |
|---|
| 1614 | 1747 | |
|---|
| 1615 | 1748 | for (i = 0; i < count; i++) { |
|---|
| 1616 | 1749 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; |
|---|
| 1617 | | - if (widget->size != sizeof(*widget)) { |
|---|
| 1750 | + if (le32_to_cpu(widget->size) != sizeof(*widget)) { |
|---|
| 1618 | 1751 | dev_err(tplg->dev, "ASoC: invalid widget size\n"); |
|---|
| 1619 | 1752 | return -EINVAL; |
|---|
| 1620 | 1753 | } |
|---|
| .. | .. |
|---|
| 1652 | 1785 | return 0; |
|---|
| 1653 | 1786 | } |
|---|
| 1654 | 1787 | |
|---|
| 1655 | | -static void set_stream_info(struct snd_soc_pcm_stream *stream, |
|---|
| 1788 | +static int set_stream_info(struct snd_soc_pcm_stream *stream, |
|---|
| 1656 | 1789 | struct snd_soc_tplg_stream_caps *caps) |
|---|
| 1657 | 1790 | { |
|---|
| 1658 | 1791 | stream->stream_name = kstrdup(caps->name, GFP_KERNEL); |
|---|
| 1659 | | - stream->channels_min = caps->channels_min; |
|---|
| 1660 | | - stream->channels_max = caps->channels_max; |
|---|
| 1661 | | - stream->rates = caps->rates; |
|---|
| 1662 | | - stream->rate_min = caps->rate_min; |
|---|
| 1663 | | - stream->rate_max = caps->rate_max; |
|---|
| 1664 | | - stream->formats = caps->formats; |
|---|
| 1665 | | - stream->sig_bits = caps->sig_bits; |
|---|
| 1792 | + if (!stream->stream_name) |
|---|
| 1793 | + return -ENOMEM; |
|---|
| 1794 | + |
|---|
| 1795 | + stream->channels_min = le32_to_cpu(caps->channels_min); |
|---|
| 1796 | + stream->channels_max = le32_to_cpu(caps->channels_max); |
|---|
| 1797 | + stream->rates = le32_to_cpu(caps->rates); |
|---|
| 1798 | + stream->rate_min = le32_to_cpu(caps->rate_min); |
|---|
| 1799 | + stream->rate_max = le32_to_cpu(caps->rate_max); |
|---|
| 1800 | + stream->formats = le64_to_cpu(caps->formats); |
|---|
| 1801 | + stream->sig_bits = le32_to_cpu(caps->sig_bits); |
|---|
| 1802 | + |
|---|
| 1803 | + return 0; |
|---|
| 1666 | 1804 | } |
|---|
| 1667 | 1805 | |
|---|
| 1668 | 1806 | static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, |
|---|
| .. | .. |
|---|
| 1689 | 1827 | struct snd_soc_dai_driver *dai_drv; |
|---|
| 1690 | 1828 | struct snd_soc_pcm_stream *stream; |
|---|
| 1691 | 1829 | struct snd_soc_tplg_stream_caps *caps; |
|---|
| 1830 | + struct snd_soc_dai *dai; |
|---|
| 1831 | + struct snd_soc_dapm_context *dapm = |
|---|
| 1832 | + snd_soc_component_get_dapm(tplg->comp); |
|---|
| 1692 | 1833 | int ret; |
|---|
| 1693 | 1834 | |
|---|
| 1694 | 1835 | dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL); |
|---|
| 1695 | 1836 | if (dai_drv == NULL) |
|---|
| 1696 | 1837 | return -ENOMEM; |
|---|
| 1697 | 1838 | |
|---|
| 1698 | | - if (strlen(pcm->dai_name)) |
|---|
| 1839 | + if (strlen(pcm->dai_name)) { |
|---|
| 1699 | 1840 | dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL); |
|---|
| 1700 | | - dai_drv->id = pcm->dai_id; |
|---|
| 1841 | + if (!dai_drv->name) { |
|---|
| 1842 | + ret = -ENOMEM; |
|---|
| 1843 | + goto err; |
|---|
| 1844 | + } |
|---|
| 1845 | + } |
|---|
| 1846 | + dai_drv->id = le32_to_cpu(pcm->dai_id); |
|---|
| 1701 | 1847 | |
|---|
| 1702 | 1848 | if (pcm->playback) { |
|---|
| 1703 | 1849 | stream = &dai_drv->playback; |
|---|
| 1704 | 1850 | caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; |
|---|
| 1705 | | - set_stream_info(stream, caps); |
|---|
| 1851 | + ret = set_stream_info(stream, caps); |
|---|
| 1852 | + if (ret < 0) |
|---|
| 1853 | + goto err; |
|---|
| 1706 | 1854 | } |
|---|
| 1707 | 1855 | |
|---|
| 1708 | 1856 | if (pcm->capture) { |
|---|
| 1709 | 1857 | stream = &dai_drv->capture; |
|---|
| 1710 | 1858 | caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE]; |
|---|
| 1711 | | - set_stream_info(stream, caps); |
|---|
| 1859 | + ret = set_stream_info(stream, caps); |
|---|
| 1860 | + if (ret < 0) |
|---|
| 1861 | + goto err; |
|---|
| 1712 | 1862 | } |
|---|
| 1713 | 1863 | |
|---|
| 1714 | 1864 | if (pcm->compress) |
|---|
| .. | .. |
|---|
| 1718 | 1868 | ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); |
|---|
| 1719 | 1869 | if (ret < 0) { |
|---|
| 1720 | 1870 | dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); |
|---|
| 1721 | | - kfree(dai_drv); |
|---|
| 1722 | | - return ret; |
|---|
| 1871 | + goto err; |
|---|
| 1723 | 1872 | } |
|---|
| 1724 | 1873 | |
|---|
| 1725 | 1874 | dai_drv->dobj.index = tplg->index; |
|---|
| .. | .. |
|---|
| 1728 | 1877 | list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); |
|---|
| 1729 | 1878 | |
|---|
| 1730 | 1879 | /* register the DAI to the component */ |
|---|
| 1731 | | - return snd_soc_register_dai(tplg->comp, dai_drv); |
|---|
| 1880 | + dai = snd_soc_register_dai(tplg->comp, dai_drv, false); |
|---|
| 1881 | + if (!dai) |
|---|
| 1882 | + return -ENOMEM; |
|---|
| 1883 | + |
|---|
| 1884 | + /* Create the DAI widgets here */ |
|---|
| 1885 | + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); |
|---|
| 1886 | + if (ret != 0) { |
|---|
| 1887 | + dev_err(dai->dev, "Failed to create DAI widgets %d\n", ret); |
|---|
| 1888 | + snd_soc_unregister_dai(dai); |
|---|
| 1889 | + return ret; |
|---|
| 1890 | + } |
|---|
| 1891 | + |
|---|
| 1892 | + return 0; |
|---|
| 1893 | + |
|---|
| 1894 | +err: |
|---|
| 1895 | + kfree(dai_drv->playback.stream_name); |
|---|
| 1896 | + kfree(dai_drv->capture.stream_name); |
|---|
| 1897 | + kfree(dai_drv->name); |
|---|
| 1898 | + kfree(dai_drv); |
|---|
| 1899 | + |
|---|
| 1900 | + return ret; |
|---|
| 1732 | 1901 | } |
|---|
| 1733 | 1902 | |
|---|
| 1734 | 1903 | static void set_link_flags(struct snd_soc_dai_link *link, |
|---|
| .. | .. |
|---|
| 1759 | 1928 | struct snd_soc_tplg_pcm *pcm) |
|---|
| 1760 | 1929 | { |
|---|
| 1761 | 1930 | struct snd_soc_dai_link *link; |
|---|
| 1931 | + struct snd_soc_dai_link_component *dlc; |
|---|
| 1762 | 1932 | int ret; |
|---|
| 1763 | 1933 | |
|---|
| 1764 | | - link = kzalloc(sizeof(struct snd_soc_dai_link), GFP_KERNEL); |
|---|
| 1934 | + /* link + cpu + codec + platform */ |
|---|
| 1935 | + link = kzalloc(sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL); |
|---|
| 1765 | 1936 | if (link == NULL) |
|---|
| 1766 | 1937 | return -ENOMEM; |
|---|
| 1938 | + |
|---|
| 1939 | + dlc = (struct snd_soc_dai_link_component *)(link + 1); |
|---|
| 1940 | + |
|---|
| 1941 | + link->cpus = &dlc[0]; |
|---|
| 1942 | + link->codecs = &dlc[1]; |
|---|
| 1943 | + link->platforms = &dlc[2]; |
|---|
| 1944 | + |
|---|
| 1945 | + link->num_cpus = 1; |
|---|
| 1946 | + link->num_codecs = 1; |
|---|
| 1947 | + link->num_platforms = 1; |
|---|
| 1948 | + |
|---|
| 1949 | + link->dobj.index = tplg->index; |
|---|
| 1950 | + link->dobj.ops = tplg->ops; |
|---|
| 1951 | + link->dobj.type = SND_SOC_DOBJ_DAI_LINK; |
|---|
| 1767 | 1952 | |
|---|
| 1768 | 1953 | if (strlen(pcm->pcm_name)) { |
|---|
| 1769 | 1954 | link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); |
|---|
| 1770 | 1955 | link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL); |
|---|
| 1956 | + if (!link->name || !link->stream_name) { |
|---|
| 1957 | + ret = -ENOMEM; |
|---|
| 1958 | + goto err; |
|---|
| 1959 | + } |
|---|
| 1771 | 1960 | } |
|---|
| 1772 | | - link->id = pcm->pcm_id; |
|---|
| 1961 | + link->id = le32_to_cpu(pcm->pcm_id); |
|---|
| 1773 | 1962 | |
|---|
| 1774 | | - if (strlen(pcm->dai_name)) |
|---|
| 1775 | | - link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); |
|---|
| 1963 | + if (strlen(pcm->dai_name)) { |
|---|
| 1964 | + link->cpus->dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); |
|---|
| 1965 | + if (!link->cpus->dai_name) { |
|---|
| 1966 | + ret = -ENOMEM; |
|---|
| 1967 | + goto err; |
|---|
| 1968 | + } |
|---|
| 1969 | + } |
|---|
| 1776 | 1970 | |
|---|
| 1777 | | - link->codec_name = "snd-soc-dummy"; |
|---|
| 1778 | | - link->codec_dai_name = "snd-soc-dummy-dai"; |
|---|
| 1971 | + link->codecs->name = "snd-soc-dummy"; |
|---|
| 1972 | + link->codecs->dai_name = "snd-soc-dummy-dai"; |
|---|
| 1973 | + |
|---|
| 1974 | + link->platforms->name = "snd-soc-dummy"; |
|---|
| 1779 | 1975 | |
|---|
| 1780 | 1976 | /* enable DPCM */ |
|---|
| 1781 | 1977 | link->dynamic = 1; |
|---|
| 1782 | | - link->dpcm_playback = pcm->playback; |
|---|
| 1783 | | - link->dpcm_capture = pcm->capture; |
|---|
| 1978 | + link->dpcm_playback = le32_to_cpu(pcm->playback); |
|---|
| 1979 | + link->dpcm_capture = le32_to_cpu(pcm->capture); |
|---|
| 1784 | 1980 | if (pcm->flag_mask) |
|---|
| 1785 | | - set_link_flags(link, pcm->flag_mask, pcm->flags); |
|---|
| 1981 | + set_link_flags(link, |
|---|
| 1982 | + le32_to_cpu(pcm->flag_mask), |
|---|
| 1983 | + le32_to_cpu(pcm->flags)); |
|---|
| 1786 | 1984 | |
|---|
| 1787 | 1985 | /* pass control to component driver for optional further init */ |
|---|
| 1788 | 1986 | ret = soc_tplg_dai_link_load(tplg, link, NULL); |
|---|
| 1789 | 1987 | if (ret < 0) { |
|---|
| 1790 | 1988 | dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n"); |
|---|
| 1791 | | - kfree(link); |
|---|
| 1792 | | - return ret; |
|---|
| 1989 | + goto err; |
|---|
| 1793 | 1990 | } |
|---|
| 1794 | 1991 | |
|---|
| 1795 | | - link->dobj.index = tplg->index; |
|---|
| 1796 | | - link->dobj.ops = tplg->ops; |
|---|
| 1797 | | - link->dobj.type = SND_SOC_DOBJ_DAI_LINK; |
|---|
| 1992 | + ret = snd_soc_add_pcm_runtime(tplg->comp->card, link); |
|---|
| 1993 | + if (ret < 0) { |
|---|
| 1994 | + dev_err(tplg->comp->dev, "ASoC: adding FE link failed\n"); |
|---|
| 1995 | + goto err; |
|---|
| 1996 | + } |
|---|
| 1997 | + |
|---|
| 1798 | 1998 | list_add(&link->dobj.list, &tplg->comp->dobj_list); |
|---|
| 1799 | 1999 | |
|---|
| 1800 | | - snd_soc_add_dai_link(tplg->comp->card, link); |
|---|
| 1801 | 2000 | return 0; |
|---|
| 2001 | +err: |
|---|
| 2002 | + kfree(link->name); |
|---|
| 2003 | + kfree(link->stream_name); |
|---|
| 2004 | + kfree(link->cpus->dai_name); |
|---|
| 2005 | + kfree(link); |
|---|
| 2006 | + return ret; |
|---|
| 1802 | 2007 | } |
|---|
| 1803 | 2008 | |
|---|
| 1804 | 2009 | /* create a FE DAI and DAI link from the PCM object */ |
|---|
| .. | .. |
|---|
| 1818 | 2023 | static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest, |
|---|
| 1819 | 2024 | struct snd_soc_tplg_stream_caps_v4 *src) |
|---|
| 1820 | 2025 | { |
|---|
| 1821 | | - dest->size = sizeof(*dest); |
|---|
| 2026 | + dest->size = cpu_to_le32(sizeof(*dest)); |
|---|
| 1822 | 2027 | memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); |
|---|
| 1823 | 2028 | dest->formats = src->formats; |
|---|
| 1824 | 2029 | dest->rates = src->rates; |
|---|
| .. | .. |
|---|
| 1852 | 2057 | |
|---|
| 1853 | 2058 | *pcm = NULL; |
|---|
| 1854 | 2059 | |
|---|
| 1855 | | - if (src->size != sizeof(*src_v4)) { |
|---|
| 2060 | + if (le32_to_cpu(src->size) != sizeof(*src_v4)) { |
|---|
| 1856 | 2061 | dev_err(tplg->dev, "ASoC: invalid PCM size\n"); |
|---|
| 1857 | 2062 | return -EINVAL; |
|---|
| 1858 | 2063 | } |
|---|
| .. | .. |
|---|
| 1863 | 2068 | if (!dest) |
|---|
| 1864 | 2069 | return -ENOMEM; |
|---|
| 1865 | 2070 | |
|---|
| 1866 | | - dest->size = sizeof(*dest); /* size of latest abi version */ |
|---|
| 2071 | + dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */ |
|---|
| 1867 | 2072 | memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); |
|---|
| 1868 | 2073 | memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); |
|---|
| 1869 | 2074 | dest->pcm_id = src_v4->pcm_id; |
|---|
| .. | .. |
|---|
| 1872 | 2077 | dest->capture = src_v4->capture; |
|---|
| 1873 | 2078 | dest->compress = src_v4->compress; |
|---|
| 1874 | 2079 | dest->num_streams = src_v4->num_streams; |
|---|
| 1875 | | - for (i = 0; i < dest->num_streams; i++) |
|---|
| 2080 | + for (i = 0; i < le32_to_cpu(dest->num_streams); i++) |
|---|
| 1876 | 2081 | memcpy(&dest->stream[i], &src_v4->stream[i], |
|---|
| 1877 | 2082 | sizeof(struct snd_soc_tplg_stream)); |
|---|
| 1878 | 2083 | |
|---|
| .. | .. |
|---|
| 1887 | 2092 | struct snd_soc_tplg_hdr *hdr) |
|---|
| 1888 | 2093 | { |
|---|
| 1889 | 2094 | struct snd_soc_tplg_pcm *pcm, *_pcm; |
|---|
| 1890 | | - int count = hdr->count; |
|---|
| 2095 | + int count; |
|---|
| 2096 | + int size; |
|---|
| 1891 | 2097 | int i; |
|---|
| 1892 | 2098 | bool abi_match; |
|---|
| 1893 | 2099 | int ret; |
|---|
| 1894 | 2100 | |
|---|
| 1895 | | - if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) |
|---|
| 1896 | | - return 0; |
|---|
| 2101 | + count = le32_to_cpu(hdr->count); |
|---|
| 1897 | 2102 | |
|---|
| 1898 | 2103 | /* check the element size and count */ |
|---|
| 1899 | 2104 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; |
|---|
| 1900 | | - if (pcm->size > sizeof(struct snd_soc_tplg_pcm) |
|---|
| 1901 | | - || pcm->size < sizeof(struct snd_soc_tplg_pcm_v4)) { |
|---|
| 2105 | + size = le32_to_cpu(pcm->size); |
|---|
| 2106 | + if (size > sizeof(struct snd_soc_tplg_pcm) |
|---|
| 2107 | + || size < sizeof(struct snd_soc_tplg_pcm_v4)) { |
|---|
| 1902 | 2108 | dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n", |
|---|
| 1903 | | - pcm->size); |
|---|
| 2109 | + size); |
|---|
| 1904 | 2110 | return -EINVAL; |
|---|
| 1905 | 2111 | } |
|---|
| 1906 | 2112 | |
|---|
| 1907 | 2113 | if (soc_tplg_check_elem_count(tplg, |
|---|
| 1908 | | - pcm->size, count, |
|---|
| 1909 | | - hdr->payload_size, "PCM DAI")) { |
|---|
| 2114 | + size, count, |
|---|
| 2115 | + le32_to_cpu(hdr->payload_size), |
|---|
| 2116 | + "PCM DAI")) { |
|---|
| 1910 | 2117 | dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n", |
|---|
| 1911 | 2118 | count); |
|---|
| 1912 | 2119 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1914 | 2121 | |
|---|
| 1915 | 2122 | for (i = 0; i < count; i++) { |
|---|
| 1916 | 2123 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; |
|---|
| 2124 | + size = le32_to_cpu(pcm->size); |
|---|
| 1917 | 2125 | |
|---|
| 1918 | 2126 | /* check ABI version by size, create a new version of pcm |
|---|
| 1919 | 2127 | * if abi not match. |
|---|
| 1920 | 2128 | */ |
|---|
| 1921 | | - if (pcm->size == sizeof(*pcm)) { |
|---|
| 2129 | + if (size == sizeof(*pcm)) { |
|---|
| 1922 | 2130 | abi_match = true; |
|---|
| 1923 | 2131 | _pcm = pcm; |
|---|
| 1924 | 2132 | } else { |
|---|
| .. | .. |
|---|
| 1939 | 2147 | /* offset by version-specific struct size and |
|---|
| 1940 | 2148 | * real priv data size |
|---|
| 1941 | 2149 | */ |
|---|
| 1942 | | - tplg->pos += pcm->size + _pcm->priv.size; |
|---|
| 2150 | + tplg->pos += size + le32_to_cpu(_pcm->priv.size); |
|---|
| 1943 | 2151 | |
|---|
| 1944 | 2152 | if (!abi_match) |
|---|
| 1945 | 2153 | kfree(_pcm); /* free the duplicated one */ |
|---|
| .. | .. |
|---|
| 1967 | 2175 | unsigned char invert_bclk, invert_fsync; |
|---|
| 1968 | 2176 | int i; |
|---|
| 1969 | 2177 | |
|---|
| 1970 | | - for (i = 0; i < cfg->num_hw_configs; i++) { |
|---|
| 2178 | + for (i = 0; i < le32_to_cpu(cfg->num_hw_configs); i++) { |
|---|
| 1971 | 2179 | hw_config = &cfg->hw_config[i]; |
|---|
| 1972 | 2180 | if (hw_config->id != cfg->default_hw_config_id) |
|---|
| 1973 | 2181 | continue; |
|---|
| 1974 | 2182 | |
|---|
| 1975 | | - link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; |
|---|
| 2183 | + link->dai_fmt = le32_to_cpu(hw_config->fmt) & |
|---|
| 2184 | + SND_SOC_DAIFMT_FORMAT_MASK; |
|---|
| 1976 | 2185 | |
|---|
| 1977 | 2186 | /* clock gating */ |
|---|
| 1978 | 2187 | switch (hw_config->clock_gated) { |
|---|
| .. | .. |
|---|
| 2036 | 2245 | |
|---|
| 2037 | 2246 | *link = NULL; |
|---|
| 2038 | 2247 | |
|---|
| 2039 | | - if (src->size != sizeof(struct snd_soc_tplg_link_config_v4)) { |
|---|
| 2248 | + if (le32_to_cpu(src->size) != |
|---|
| 2249 | + sizeof(struct snd_soc_tplg_link_config_v4)) { |
|---|
| 2040 | 2250 | dev_err(tplg->dev, "ASoC: invalid physical link config size\n"); |
|---|
| 2041 | 2251 | return -EINVAL; |
|---|
| 2042 | 2252 | } |
|---|
| .. | .. |
|---|
| 2048 | 2258 | if (!dest) |
|---|
| 2049 | 2259 | return -ENOMEM; |
|---|
| 2050 | 2260 | |
|---|
| 2051 | | - dest->size = sizeof(*dest); |
|---|
| 2261 | + dest->size = cpu_to_le32(sizeof(*dest)); |
|---|
| 2052 | 2262 | dest->id = src_v4->id; |
|---|
| 2053 | 2263 | dest->num_streams = src_v4->num_streams; |
|---|
| 2054 | | - for (i = 0; i < dest->num_streams; i++) |
|---|
| 2264 | + for (i = 0; i < le32_to_cpu(dest->num_streams); i++) |
|---|
| 2055 | 2265 | memcpy(&dest->stream[i], &src_v4->stream[i], |
|---|
| 2056 | 2266 | sizeof(struct snd_soc_tplg_stream)); |
|---|
| 2057 | 2267 | |
|---|
| 2058 | 2268 | *link = dest; |
|---|
| 2059 | 2269 | return 0; |
|---|
| 2270 | +} |
|---|
| 2271 | + |
|---|
| 2272 | +/** |
|---|
| 2273 | + * snd_soc_find_dai_link - Find a DAI link |
|---|
| 2274 | + * |
|---|
| 2275 | + * @card: soc card |
|---|
| 2276 | + * @id: DAI link ID to match |
|---|
| 2277 | + * @name: DAI link name to match, optional |
|---|
| 2278 | + * @stream_name: DAI link stream name to match, optional |
|---|
| 2279 | + * |
|---|
| 2280 | + * This function will search all existing DAI links of the soc card to |
|---|
| 2281 | + * find the link of the same ID. Since DAI links may not have their |
|---|
| 2282 | + * unique ID, so name and stream name should also match if being |
|---|
| 2283 | + * specified. |
|---|
| 2284 | + * |
|---|
| 2285 | + * Return: pointer of DAI link, or NULL if not found. |
|---|
| 2286 | + */ |
|---|
| 2287 | +static struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, |
|---|
| 2288 | + int id, const char *name, |
|---|
| 2289 | + const char *stream_name) |
|---|
| 2290 | +{ |
|---|
| 2291 | + struct snd_soc_pcm_runtime *rtd; |
|---|
| 2292 | + struct snd_soc_dai_link *link; |
|---|
| 2293 | + |
|---|
| 2294 | + for_each_card_rtds(card, rtd) { |
|---|
| 2295 | + link = rtd->dai_link; |
|---|
| 2296 | + |
|---|
| 2297 | + if (link->id != id) |
|---|
| 2298 | + continue; |
|---|
| 2299 | + |
|---|
| 2300 | + if (name && (!link->name || strcmp(name, link->name))) |
|---|
| 2301 | + continue; |
|---|
| 2302 | + |
|---|
| 2303 | + if (stream_name && (!link->stream_name |
|---|
| 2304 | + || strcmp(stream_name, link->stream_name))) |
|---|
| 2305 | + continue; |
|---|
| 2306 | + |
|---|
| 2307 | + return link; |
|---|
| 2308 | + } |
|---|
| 2309 | + |
|---|
| 2310 | + return NULL; |
|---|
| 2060 | 2311 | } |
|---|
| 2061 | 2312 | |
|---|
| 2062 | 2313 | /* Find and configure an existing physical DAI link */ |
|---|
| .. | .. |
|---|
| 2084 | 2335 | else |
|---|
| 2085 | 2336 | stream_name = NULL; |
|---|
| 2086 | 2337 | |
|---|
| 2087 | | - link = snd_soc_find_dai_link(tplg->comp->card, cfg->id, |
|---|
| 2338 | + link = snd_soc_find_dai_link(tplg->comp->card, le32_to_cpu(cfg->id), |
|---|
| 2088 | 2339 | name, stream_name); |
|---|
| 2089 | 2340 | if (!link) { |
|---|
| 2090 | 2341 | dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n", |
|---|
| .. | .. |
|---|
| 2098 | 2349 | |
|---|
| 2099 | 2350 | /* flags */ |
|---|
| 2100 | 2351 | if (cfg->flag_mask) |
|---|
| 2101 | | - set_link_flags(link, cfg->flag_mask, cfg->flags); |
|---|
| 2352 | + set_link_flags(link, |
|---|
| 2353 | + le32_to_cpu(cfg->flag_mask), |
|---|
| 2354 | + le32_to_cpu(cfg->flags)); |
|---|
| 2102 | 2355 | |
|---|
| 2103 | 2356 | /* pass control to component driver for optional further init */ |
|---|
| 2104 | 2357 | ret = soc_tplg_dai_link_load(tplg, link, cfg); |
|---|
| .. | .. |
|---|
| 2106 | 2359 | dev_err(tplg->dev, "ASoC: physical link loading failed\n"); |
|---|
| 2107 | 2360 | return ret; |
|---|
| 2108 | 2361 | } |
|---|
| 2362 | + |
|---|
| 2363 | + /* for unloading it in snd_soc_tplg_component_remove */ |
|---|
| 2364 | + link->dobj.index = tplg->index; |
|---|
| 2365 | + link->dobj.ops = tplg->ops; |
|---|
| 2366 | + link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; |
|---|
| 2367 | + list_add(&link->dobj.list, &tplg->comp->dobj_list); |
|---|
| 2109 | 2368 | |
|---|
| 2110 | 2369 | return 0; |
|---|
| 2111 | 2370 | } |
|---|
| .. | .. |
|---|
| 2116 | 2375 | struct snd_soc_tplg_hdr *hdr) |
|---|
| 2117 | 2376 | { |
|---|
| 2118 | 2377 | struct snd_soc_tplg_link_config *link, *_link; |
|---|
| 2119 | | - int count = hdr->count; |
|---|
| 2378 | + int count; |
|---|
| 2379 | + int size; |
|---|
| 2120 | 2380 | int i, ret; |
|---|
| 2121 | 2381 | bool abi_match; |
|---|
| 2122 | 2382 | |
|---|
| 2123 | | - if (tplg->pass != SOC_TPLG_PASS_LINK) { |
|---|
| 2124 | | - tplg->pos += hdr->size + hdr->payload_size; |
|---|
| 2125 | | - return 0; |
|---|
| 2126 | | - }; |
|---|
| 2383 | + count = le32_to_cpu(hdr->count); |
|---|
| 2127 | 2384 | |
|---|
| 2128 | 2385 | /* check the element size and count */ |
|---|
| 2129 | 2386 | link = (struct snd_soc_tplg_link_config *)tplg->pos; |
|---|
| 2130 | | - if (link->size > sizeof(struct snd_soc_tplg_link_config) |
|---|
| 2131 | | - || link->size < sizeof(struct snd_soc_tplg_link_config_v4)) { |
|---|
| 2387 | + size = le32_to_cpu(link->size); |
|---|
| 2388 | + if (size > sizeof(struct snd_soc_tplg_link_config) |
|---|
| 2389 | + || size < sizeof(struct snd_soc_tplg_link_config_v4)) { |
|---|
| 2132 | 2390 | dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n", |
|---|
| 2133 | | - link->size); |
|---|
| 2391 | + size); |
|---|
| 2134 | 2392 | return -EINVAL; |
|---|
| 2135 | 2393 | } |
|---|
| 2136 | 2394 | |
|---|
| 2137 | 2395 | if (soc_tplg_check_elem_count(tplg, |
|---|
| 2138 | | - link->size, count, |
|---|
| 2139 | | - hdr->payload_size, "physical link config")) { |
|---|
| 2396 | + size, count, |
|---|
| 2397 | + le32_to_cpu(hdr->payload_size), |
|---|
| 2398 | + "physical link config")) { |
|---|
| 2140 | 2399 | dev_err(tplg->dev, "ASoC: invalid count %d for physical link elems\n", |
|---|
| 2141 | 2400 | count); |
|---|
| 2142 | 2401 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 2145 | 2404 | /* config physical DAI links */ |
|---|
| 2146 | 2405 | for (i = 0; i < count; i++) { |
|---|
| 2147 | 2406 | link = (struct snd_soc_tplg_link_config *)tplg->pos; |
|---|
| 2148 | | - if (link->size == sizeof(*link)) { |
|---|
| 2407 | + size = le32_to_cpu(link->size); |
|---|
| 2408 | + if (size == sizeof(*link)) { |
|---|
| 2149 | 2409 | abi_match = true; |
|---|
| 2150 | 2410 | _link = link; |
|---|
| 2151 | 2411 | } else { |
|---|
| .. | .. |
|---|
| 2165 | 2425 | /* offset by version-specific struct size and |
|---|
| 2166 | 2426 | * real priv data size |
|---|
| 2167 | 2427 | */ |
|---|
| 2168 | | - tplg->pos += link->size + _link->priv.size; |
|---|
| 2428 | + tplg->pos += size + le32_to_cpu(_link->priv.size); |
|---|
| 2169 | 2429 | |
|---|
| 2170 | 2430 | if (!abi_match) |
|---|
| 2171 | 2431 | kfree(_link); /* free the duplicated one */ |
|---|
| .. | .. |
|---|
| 2185 | 2445 | static int soc_tplg_dai_config(struct soc_tplg *tplg, |
|---|
| 2186 | 2446 | struct snd_soc_tplg_dai *d) |
|---|
| 2187 | 2447 | { |
|---|
| 2188 | | - struct snd_soc_dai_link_component dai_component = {0}; |
|---|
| 2448 | + struct snd_soc_dai_link_component dai_component; |
|---|
| 2189 | 2449 | struct snd_soc_dai *dai; |
|---|
| 2190 | 2450 | struct snd_soc_dai_driver *dai_drv; |
|---|
| 2191 | 2451 | struct snd_soc_pcm_stream *stream; |
|---|
| 2192 | 2452 | struct snd_soc_tplg_stream_caps *caps; |
|---|
| 2193 | 2453 | int ret; |
|---|
| 2454 | + |
|---|
| 2455 | + memset(&dai_component, 0, sizeof(dai_component)); |
|---|
| 2194 | 2456 | |
|---|
| 2195 | 2457 | dai_component.dai_name = d->dai_name; |
|---|
| 2196 | 2458 | dai = snd_soc_find_dai(&dai_component); |
|---|
| .. | .. |
|---|
| 2200 | 2462 | return -EINVAL; |
|---|
| 2201 | 2463 | } |
|---|
| 2202 | 2464 | |
|---|
| 2203 | | - if (d->dai_id != dai->id) { |
|---|
| 2465 | + if (le32_to_cpu(d->dai_id) != dai->id) { |
|---|
| 2204 | 2466 | dev_err(tplg->dev, "ASoC: physical DAI %s id mismatch\n", |
|---|
| 2205 | 2467 | d->dai_name); |
|---|
| 2206 | 2468 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 2213 | 2475 | if (d->playback) { |
|---|
| 2214 | 2476 | stream = &dai_drv->playback; |
|---|
| 2215 | 2477 | caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; |
|---|
| 2216 | | - set_stream_info(stream, caps); |
|---|
| 2478 | + ret = set_stream_info(stream, caps); |
|---|
| 2479 | + if (ret < 0) |
|---|
| 2480 | + goto err; |
|---|
| 2217 | 2481 | } |
|---|
| 2218 | 2482 | |
|---|
| 2219 | 2483 | if (d->capture) { |
|---|
| 2220 | 2484 | stream = &dai_drv->capture; |
|---|
| 2221 | 2485 | caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE]; |
|---|
| 2222 | | - set_stream_info(stream, caps); |
|---|
| 2486 | + ret = set_stream_info(stream, caps); |
|---|
| 2487 | + if (ret < 0) |
|---|
| 2488 | + goto err; |
|---|
| 2223 | 2489 | } |
|---|
| 2224 | 2490 | |
|---|
| 2225 | 2491 | if (d->flag_mask) |
|---|
| 2226 | | - set_dai_flags(dai_drv, d->flag_mask, d->flags); |
|---|
| 2492 | + set_dai_flags(dai_drv, |
|---|
| 2493 | + le32_to_cpu(d->flag_mask), |
|---|
| 2494 | + le32_to_cpu(d->flags)); |
|---|
| 2227 | 2495 | |
|---|
| 2228 | 2496 | /* pass control to component driver for optional further init */ |
|---|
| 2229 | 2497 | ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai); |
|---|
| 2230 | 2498 | if (ret < 0) { |
|---|
| 2231 | 2499 | dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); |
|---|
| 2232 | | - return ret; |
|---|
| 2500 | + goto err; |
|---|
| 2233 | 2501 | } |
|---|
| 2234 | 2502 | |
|---|
| 2235 | 2503 | return 0; |
|---|
| 2504 | + |
|---|
| 2505 | +err: |
|---|
| 2506 | + kfree(dai_drv->playback.stream_name); |
|---|
| 2507 | + kfree(dai_drv->capture.stream_name); |
|---|
| 2508 | + return ret; |
|---|
| 2236 | 2509 | } |
|---|
| 2237 | 2510 | |
|---|
| 2238 | 2511 | /* load physical DAI elements */ |
|---|
| .. | .. |
|---|
| 2240 | 2513 | struct snd_soc_tplg_hdr *hdr) |
|---|
| 2241 | 2514 | { |
|---|
| 2242 | 2515 | struct snd_soc_tplg_dai *dai; |
|---|
| 2243 | | - int count = hdr->count; |
|---|
| 2244 | | - int i; |
|---|
| 2516 | + int count; |
|---|
| 2517 | + int i, ret; |
|---|
| 2245 | 2518 | |
|---|
| 2246 | | - if (tplg->pass != SOC_TPLG_PASS_BE_DAI) |
|---|
| 2247 | | - return 0; |
|---|
| 2519 | + count = le32_to_cpu(hdr->count); |
|---|
| 2248 | 2520 | |
|---|
| 2249 | 2521 | /* config the existing BE DAIs */ |
|---|
| 2250 | 2522 | for (i = 0; i < count; i++) { |
|---|
| 2251 | 2523 | dai = (struct snd_soc_tplg_dai *)tplg->pos; |
|---|
| 2252 | | - if (dai->size != sizeof(*dai)) { |
|---|
| 2524 | + if (le32_to_cpu(dai->size) != sizeof(*dai)) { |
|---|
| 2253 | 2525 | dev_err(tplg->dev, "ASoC: invalid physical DAI size\n"); |
|---|
| 2254 | 2526 | return -EINVAL; |
|---|
| 2255 | 2527 | } |
|---|
| 2256 | 2528 | |
|---|
| 2257 | | - soc_tplg_dai_config(tplg, dai); |
|---|
| 2258 | | - tplg->pos += (sizeof(*dai) + dai->priv.size); |
|---|
| 2529 | + ret = soc_tplg_dai_config(tplg, dai); |
|---|
| 2530 | + if (ret < 0) { |
|---|
| 2531 | + dev_err(tplg->dev, "ASoC: failed to configure DAI\n"); |
|---|
| 2532 | + return ret; |
|---|
| 2533 | + } |
|---|
| 2534 | + |
|---|
| 2535 | + tplg->pos += (sizeof(*dai) + le32_to_cpu(dai->priv.size)); |
|---|
| 2259 | 2536 | } |
|---|
| 2260 | 2537 | |
|---|
| 2261 | 2538 | dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count); |
|---|
| .. | .. |
|---|
| 2277 | 2554 | { |
|---|
| 2278 | 2555 | struct snd_soc_tplg_manifest *dest; |
|---|
| 2279 | 2556 | struct snd_soc_tplg_manifest_v4 *src_v4; |
|---|
| 2557 | + int size; |
|---|
| 2280 | 2558 | |
|---|
| 2281 | 2559 | *manifest = NULL; |
|---|
| 2282 | 2560 | |
|---|
| 2283 | | - if (src->size != sizeof(*src_v4)) { |
|---|
| 2561 | + size = le32_to_cpu(src->size); |
|---|
| 2562 | + if (size != sizeof(*src_v4)) { |
|---|
| 2284 | 2563 | dev_warn(tplg->dev, "ASoC: invalid manifest size %d\n", |
|---|
| 2285 | | - src->size); |
|---|
| 2286 | | - if (src->size) |
|---|
| 2564 | + size); |
|---|
| 2565 | + if (size) |
|---|
| 2287 | 2566 | return -EINVAL; |
|---|
| 2288 | | - src->size = sizeof(*src_v4); |
|---|
| 2567 | + src->size = cpu_to_le32(sizeof(*src_v4)); |
|---|
| 2289 | 2568 | } |
|---|
| 2290 | 2569 | |
|---|
| 2291 | 2570 | dev_warn(tplg->dev, "ASoC: old version of manifest\n"); |
|---|
| 2292 | 2571 | |
|---|
| 2293 | 2572 | src_v4 = (struct snd_soc_tplg_manifest_v4 *)src; |
|---|
| 2294 | | - dest = kzalloc(sizeof(*dest) + src_v4->priv.size, GFP_KERNEL); |
|---|
| 2573 | + dest = kzalloc(sizeof(*dest) + le32_to_cpu(src_v4->priv.size), |
|---|
| 2574 | + GFP_KERNEL); |
|---|
| 2295 | 2575 | if (!dest) |
|---|
| 2296 | 2576 | return -ENOMEM; |
|---|
| 2297 | 2577 | |
|---|
| 2298 | | - dest->size = sizeof(*dest); /* size of latest abi version */ |
|---|
| 2578 | + dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */ |
|---|
| 2299 | 2579 | dest->control_elems = src_v4->control_elems; |
|---|
| 2300 | 2580 | dest->widget_elems = src_v4->widget_elems; |
|---|
| 2301 | 2581 | dest->graph_elems = src_v4->graph_elems; |
|---|
| .. | .. |
|---|
| 2304 | 2584 | dest->priv.size = src_v4->priv.size; |
|---|
| 2305 | 2585 | if (dest->priv.size) |
|---|
| 2306 | 2586 | memcpy(dest->priv.data, src_v4->priv.data, |
|---|
| 2307 | | - src_v4->priv.size); |
|---|
| 2587 | + le32_to_cpu(src_v4->priv.size)); |
|---|
| 2308 | 2588 | |
|---|
| 2309 | 2589 | *manifest = dest; |
|---|
| 2310 | 2590 | return 0; |
|---|
| .. | .. |
|---|
| 2317 | 2597 | bool abi_match; |
|---|
| 2318 | 2598 | int ret = 0; |
|---|
| 2319 | 2599 | |
|---|
| 2320 | | - if (tplg->pass != SOC_TPLG_PASS_MANIFEST) |
|---|
| 2321 | | - return 0; |
|---|
| 2322 | | - |
|---|
| 2323 | 2600 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; |
|---|
| 2324 | 2601 | |
|---|
| 2325 | 2602 | /* check ABI version by size, create a new manifest if abi not match */ |
|---|
| 2326 | | - if (manifest->size == sizeof(*manifest)) { |
|---|
| 2603 | + if (le32_to_cpu(manifest->size) == sizeof(*manifest)) { |
|---|
| 2327 | 2604 | abi_match = true; |
|---|
| 2328 | 2605 | _manifest = manifest; |
|---|
| 2329 | 2606 | } else { |
|---|
| .. | .. |
|---|
| 2334 | 2611 | } |
|---|
| 2335 | 2612 | |
|---|
| 2336 | 2613 | /* pass control to component driver for optional further init */ |
|---|
| 2337 | | - if (tplg->comp && tplg->ops && tplg->ops->manifest) |
|---|
| 2614 | + if (tplg->ops && tplg->ops->manifest) |
|---|
| 2338 | 2615 | ret = tplg->ops->manifest(tplg->comp, tplg->index, _manifest); |
|---|
| 2339 | 2616 | |
|---|
| 2340 | 2617 | if (!abi_match) /* free the duplicated one */ |
|---|
| .. | .. |
|---|
| 2350 | 2627 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) |
|---|
| 2351 | 2628 | return 0; |
|---|
| 2352 | 2629 | |
|---|
| 2353 | | - if (hdr->size != sizeof(*hdr)) { |
|---|
| 2630 | + if (le32_to_cpu(hdr->size) != sizeof(*hdr)) { |
|---|
| 2354 | 2631 | dev_err(tplg->dev, |
|---|
| 2355 | 2632 | "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n", |
|---|
| 2356 | | - hdr->type, soc_tplg_get_hdr_offset(tplg), |
|---|
| 2633 | + le32_to_cpu(hdr->type), soc_tplg_get_hdr_offset(tplg), |
|---|
| 2357 | 2634 | tplg->fw->size); |
|---|
| 2358 | 2635 | return -EINVAL; |
|---|
| 2359 | 2636 | } |
|---|
| 2360 | 2637 | |
|---|
| 2361 | 2638 | /* big endian firmware objects not supported atm */ |
|---|
| 2362 | | - if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { |
|---|
| 2639 | + if (le32_to_cpu(hdr->magic) == SOC_TPLG_MAGIC_BIG_ENDIAN) { |
|---|
| 2363 | 2640 | dev_err(tplg->dev, |
|---|
| 2364 | 2641 | "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n", |
|---|
| 2365 | 2642 | tplg->pass, hdr->magic, |
|---|
| .. | .. |
|---|
| 2367 | 2644 | return -EINVAL; |
|---|
| 2368 | 2645 | } |
|---|
| 2369 | 2646 | |
|---|
| 2370 | | - if (hdr->magic != SND_SOC_TPLG_MAGIC) { |
|---|
| 2647 | + if (le32_to_cpu(hdr->magic) != SND_SOC_TPLG_MAGIC) { |
|---|
| 2371 | 2648 | dev_err(tplg->dev, |
|---|
| 2372 | 2649 | "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n", |
|---|
| 2373 | 2650 | tplg->pass, hdr->magic, |
|---|
| .. | .. |
|---|
| 2376 | 2653 | } |
|---|
| 2377 | 2654 | |
|---|
| 2378 | 2655 | /* Support ABI from version 4 */ |
|---|
| 2379 | | - if (hdr->abi > SND_SOC_TPLG_ABI_VERSION |
|---|
| 2380 | | - || hdr->abi < SND_SOC_TPLG_ABI_VERSION_MIN) { |
|---|
| 2656 | + if (le32_to_cpu(hdr->abi) > SND_SOC_TPLG_ABI_VERSION || |
|---|
| 2657 | + le32_to_cpu(hdr->abi) < SND_SOC_TPLG_ABI_VERSION_MIN) { |
|---|
| 2381 | 2658 | dev_err(tplg->dev, |
|---|
| 2382 | 2659 | "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n", |
|---|
| 2383 | 2660 | tplg->pass, hdr->abi, |
|---|
| .. | .. |
|---|
| 2392 | 2669 | return -EINVAL; |
|---|
| 2393 | 2670 | } |
|---|
| 2394 | 2671 | |
|---|
| 2395 | | - if (tplg->pass == hdr->type) |
|---|
| 2396 | | - dev_dbg(tplg->dev, |
|---|
| 2397 | | - "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n", |
|---|
| 2398 | | - hdr->payload_size, hdr->type, hdr->version, |
|---|
| 2399 | | - hdr->vendor_type, tplg->pass); |
|---|
| 2400 | | - |
|---|
| 2401 | 2672 | return 1; |
|---|
| 2402 | 2673 | } |
|---|
| 2403 | 2674 | |
|---|
| .. | .. |
|---|
| 2405 | 2676 | static int soc_tplg_load_header(struct soc_tplg *tplg, |
|---|
| 2406 | 2677 | struct snd_soc_tplg_hdr *hdr) |
|---|
| 2407 | 2678 | { |
|---|
| 2679 | + int (*elem_load)(struct soc_tplg *tplg, |
|---|
| 2680 | + struct snd_soc_tplg_hdr *hdr); |
|---|
| 2681 | + unsigned int hdr_pass; |
|---|
| 2682 | + |
|---|
| 2408 | 2683 | tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr); |
|---|
| 2409 | 2684 | |
|---|
| 2410 | 2685 | /* check for matching ID */ |
|---|
| 2411 | | - if (hdr->index != tplg->req_index && |
|---|
| 2686 | + if (le32_to_cpu(hdr->index) != tplg->req_index && |
|---|
| 2412 | 2687 | tplg->req_index != SND_SOC_TPLG_INDEX_ALL) |
|---|
| 2413 | 2688 | return 0; |
|---|
| 2414 | 2689 | |
|---|
| 2415 | | - tplg->index = hdr->index; |
|---|
| 2690 | + tplg->index = le32_to_cpu(hdr->index); |
|---|
| 2416 | 2691 | |
|---|
| 2417 | | - switch (hdr->type) { |
|---|
| 2692 | + switch (le32_to_cpu(hdr->type)) { |
|---|
| 2418 | 2693 | case SND_SOC_TPLG_TYPE_MIXER: |
|---|
| 2419 | 2694 | case SND_SOC_TPLG_TYPE_ENUM: |
|---|
| 2420 | 2695 | case SND_SOC_TPLG_TYPE_BYTES: |
|---|
| 2421 | | - return soc_tplg_kcontrol_elems_load(tplg, hdr); |
|---|
| 2696 | + hdr_pass = SOC_TPLG_PASS_MIXER; |
|---|
| 2697 | + elem_load = soc_tplg_kcontrol_elems_load; |
|---|
| 2698 | + break; |
|---|
| 2422 | 2699 | case SND_SOC_TPLG_TYPE_DAPM_GRAPH: |
|---|
| 2423 | | - return soc_tplg_dapm_graph_elems_load(tplg, hdr); |
|---|
| 2700 | + hdr_pass = SOC_TPLG_PASS_GRAPH; |
|---|
| 2701 | + elem_load = soc_tplg_dapm_graph_elems_load; |
|---|
| 2702 | + break; |
|---|
| 2424 | 2703 | case SND_SOC_TPLG_TYPE_DAPM_WIDGET: |
|---|
| 2425 | | - return soc_tplg_dapm_widget_elems_load(tplg, hdr); |
|---|
| 2704 | + hdr_pass = SOC_TPLG_PASS_WIDGET; |
|---|
| 2705 | + elem_load = soc_tplg_dapm_widget_elems_load; |
|---|
| 2706 | + break; |
|---|
| 2426 | 2707 | case SND_SOC_TPLG_TYPE_PCM: |
|---|
| 2427 | | - return soc_tplg_pcm_elems_load(tplg, hdr); |
|---|
| 2708 | + hdr_pass = SOC_TPLG_PASS_PCM_DAI; |
|---|
| 2709 | + elem_load = soc_tplg_pcm_elems_load; |
|---|
| 2710 | + break; |
|---|
| 2428 | 2711 | case SND_SOC_TPLG_TYPE_DAI: |
|---|
| 2429 | | - return soc_tplg_dai_elems_load(tplg, hdr); |
|---|
| 2712 | + hdr_pass = SOC_TPLG_PASS_BE_DAI; |
|---|
| 2713 | + elem_load = soc_tplg_dai_elems_load; |
|---|
| 2714 | + break; |
|---|
| 2430 | 2715 | case SND_SOC_TPLG_TYPE_DAI_LINK: |
|---|
| 2431 | 2716 | case SND_SOC_TPLG_TYPE_BACKEND_LINK: |
|---|
| 2432 | 2717 | /* physical link configurations */ |
|---|
| 2433 | | - return soc_tplg_link_elems_load(tplg, hdr); |
|---|
| 2718 | + hdr_pass = SOC_TPLG_PASS_LINK; |
|---|
| 2719 | + elem_load = soc_tplg_link_elems_load; |
|---|
| 2720 | + break; |
|---|
| 2434 | 2721 | case SND_SOC_TPLG_TYPE_MANIFEST: |
|---|
| 2435 | | - return soc_tplg_manifest_load(tplg, hdr); |
|---|
| 2722 | + hdr_pass = SOC_TPLG_PASS_MANIFEST; |
|---|
| 2723 | + elem_load = soc_tplg_manifest_load; |
|---|
| 2724 | + break; |
|---|
| 2436 | 2725 | default: |
|---|
| 2437 | 2726 | /* bespoke vendor data object */ |
|---|
| 2438 | | - return soc_tplg_vendor_load(tplg, hdr); |
|---|
| 2727 | + hdr_pass = SOC_TPLG_PASS_VENDOR; |
|---|
| 2728 | + elem_load = soc_tplg_vendor_load; |
|---|
| 2729 | + break; |
|---|
| 2730 | + } |
|---|
| 2731 | + |
|---|
| 2732 | + if (tplg->pass == hdr_pass) { |
|---|
| 2733 | + dev_dbg(tplg->dev, |
|---|
| 2734 | + "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n", |
|---|
| 2735 | + hdr->payload_size, hdr->type, hdr->version, |
|---|
| 2736 | + hdr->vendor_type, tplg->pass); |
|---|
| 2737 | + return elem_load(tplg, hdr); |
|---|
| 2439 | 2738 | } |
|---|
| 2440 | 2739 | |
|---|
| 2441 | 2740 | return 0; |
|---|
| .. | .. |
|---|
| 2459 | 2758 | |
|---|
| 2460 | 2759 | /* make sure header is valid before loading */ |
|---|
| 2461 | 2760 | ret = soc_valid_header(tplg, hdr); |
|---|
| 2462 | | - if (ret < 0) |
|---|
| 2761 | + if (ret < 0) { |
|---|
| 2762 | + dev_err(tplg->dev, |
|---|
| 2763 | + "ASoC: topology: invalid header: %d\n", ret); |
|---|
| 2463 | 2764 | return ret; |
|---|
| 2464 | | - else if (ret == 0) |
|---|
| 2765 | + } else if (ret == 0) { |
|---|
| 2465 | 2766 | break; |
|---|
| 2767 | + } |
|---|
| 2466 | 2768 | |
|---|
| 2467 | 2769 | /* load the header object */ |
|---|
| 2468 | 2770 | ret = soc_tplg_load_header(tplg, hdr); |
|---|
| 2469 | | - if (ret < 0) |
|---|
| 2771 | + if (ret < 0) { |
|---|
| 2772 | + dev_err(tplg->dev, |
|---|
| 2773 | + "ASoC: topology: could not load header: %d\n", ret); |
|---|
| 2470 | 2774 | return ret; |
|---|
| 2775 | + } |
|---|
| 2471 | 2776 | |
|---|
| 2472 | 2777 | /* goto next header */ |
|---|
| 2473 | | - tplg->hdr_pos += hdr->payload_size + |
|---|
| 2778 | + tplg->hdr_pos += le32_to_cpu(hdr->payload_size) + |
|---|
| 2474 | 2779 | sizeof(struct snd_soc_tplg_hdr); |
|---|
| 2475 | 2780 | hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos; |
|---|
| 2476 | 2781 | } |
|---|
| .. | .. |
|---|
| 2505 | 2810 | { |
|---|
| 2506 | 2811 | struct soc_tplg tplg; |
|---|
| 2507 | 2812 | int ret; |
|---|
| 2813 | + |
|---|
| 2814 | + /* component needs to exist to keep and reference data while parsing */ |
|---|
| 2815 | + if (!comp) |
|---|
| 2816 | + return -EINVAL; |
|---|
| 2508 | 2817 | |
|---|
| 2509 | 2818 | /* setup parsing context */ |
|---|
| 2510 | 2819 | memset(&tplg, 0, sizeof(tplg)); |
|---|
| .. | .. |
|---|
| 2544 | 2853 | { |
|---|
| 2545 | 2854 | struct snd_soc_dapm_widget *w, *next_w; |
|---|
| 2546 | 2855 | |
|---|
| 2547 | | - list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { |
|---|
| 2856 | + for_each_card_widgets_safe(dapm->card, w, next_w) { |
|---|
| 2548 | 2857 | |
|---|
| 2549 | 2858 | /* make sure we are a widget with correct context */ |
|---|
| 2550 | 2859 | if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm) |
|---|
| .. | .. |
|---|
| 2592 | 2901 | case SND_SOC_DOBJ_BYTES: |
|---|
| 2593 | 2902 | remove_bytes(comp, dobj, pass); |
|---|
| 2594 | 2903 | break; |
|---|
| 2904 | + case SND_SOC_DOBJ_GRAPH: |
|---|
| 2905 | + remove_route(comp, dobj, pass); |
|---|
| 2906 | + break; |
|---|
| 2595 | 2907 | case SND_SOC_DOBJ_WIDGET: |
|---|
| 2596 | 2908 | remove_widget(comp, dobj, pass); |
|---|
| 2597 | 2909 | break; |
|---|
| .. | .. |
|---|
| 2601 | 2913 | case SND_SOC_DOBJ_DAI_LINK: |
|---|
| 2602 | 2914 | remove_link(comp, dobj, pass); |
|---|
| 2603 | 2915 | break; |
|---|
| 2916 | + case SND_SOC_DOBJ_BACKEND_LINK: |
|---|
| 2917 | + /* |
|---|
| 2918 | + * call link_unload ops if extra |
|---|
| 2919 | + * deinitialization is needed. |
|---|
| 2920 | + */ |
|---|
| 2921 | + remove_backend_link(comp, dobj, pass); |
|---|
| 2922 | + break; |
|---|
| 2604 | 2923 | default: |
|---|
| 2605 | 2924 | dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", |
|---|
| 2606 | 2925 | dobj->type); |
|---|