.. | .. |
---|
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); |
---|