1// SPDX-License-Identifier: GPL-2.0+ 2// 3// soc-compress.c -- ALSA SoC Compress 4// 5// Copyright (C) 2012 Intel Corp. 6// 7// Authors: Namarta Kohli <namartax.kohli@intel.com> 8// Ramesh Babu K V <ramesh.babu@linux.intel.com> 9// Vinod Koul <vinod.koul@linux.intel.com> 10 11#include <linux/kernel.h> 12#include <linux/init.h> 13#include <linux/delay.h> 14#include <linux/slab.h> 15#include <linux/workqueue.h> 16#include <sound/core.h> 17#include <sound/compress_params.h> 18#include <sound/compress_driver.h> 19#include <sound/soc.h> 20#include <sound/initval.h> 21#include <sound/soc-dpcm.h> 22#include <sound/soc-link.h> 23#include <linux/pm_runtime.h> 24 25static int soc_compr_components_open(struct snd_compr_stream *cstream, 26 struct snd_soc_component **last) 27{ 28 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 29 struct snd_soc_component *component; 30 int i, ret; 31 32 for_each_rtd_components(rtd, i, component) { 33 if (!component->driver->compress_ops || 34 !component->driver->compress_ops->open) 35 continue; 36 37 ret = component->driver->compress_ops->open(component, cstream); 38 if (ret < 0) { 39 dev_err(component->dev, 40 "Compress ASoC: can't open platform %s: %d\n", 41 component->name, ret); 42 43 *last = component; 44 return ret; 45 } 46 } 47 48 *last = NULL; 49 return 0; 50} 51 52static int soc_compr_components_free(struct snd_compr_stream *cstream, 53 struct snd_soc_component *last) 54{ 55 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 56 struct snd_soc_component *component; 57 int i; 58 59 for_each_rtd_components(rtd, i, component) { 60 if (component == last) 61 break; 62 63 if (!component->driver->compress_ops || 64 !component->driver->compress_ops->free) 65 continue; 66 67 component->driver->compress_ops->free(component, cstream); 68 } 69 70 return 0; 71} 72 73static int soc_compr_open(struct snd_compr_stream *cstream) 74{ 75 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 76 struct snd_soc_component *component = NULL; 77 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 78 int ret; 79 80 ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream); 81 if (ret < 0) 82 goto pm_err; 83 84 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 85 86 ret = snd_soc_dai_compr_startup(cpu_dai, cstream); 87 if (ret < 0) 88 goto out; 89 90 ret = soc_compr_components_open(cstream, &component); 91 if (ret < 0) 92 goto machine_err; 93 94 ret = snd_soc_link_compr_startup(cstream); 95 if (ret < 0) 96 goto machine_err; 97 98 snd_soc_runtime_activate(rtd, cstream->direction); 99 100 mutex_unlock(&rtd->card->pcm_mutex); 101 102 return 0; 103 104machine_err: 105 soc_compr_components_free(cstream, component); 106 107 snd_soc_dai_compr_shutdown(cpu_dai, cstream); 108out: 109 mutex_unlock(&rtd->card->pcm_mutex); 110pm_err: 111 snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 1); 112 113 return ret; 114} 115 116static int soc_compr_open_fe(struct snd_compr_stream *cstream) 117{ 118 struct snd_soc_pcm_runtime *fe = cstream->private_data; 119 struct snd_pcm_substream *fe_substream = 120 fe->pcm->streams[cstream->direction].substream; 121 struct snd_soc_component *component; 122 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 123 struct snd_soc_dpcm *dpcm; 124 struct snd_soc_dapm_widget_list *list; 125 int stream; 126 int ret; 127 128 if (cstream->direction == SND_COMPRESS_PLAYBACK) 129 stream = SNDRV_PCM_STREAM_PLAYBACK; 130 else 131 stream = SNDRV_PCM_STREAM_CAPTURE; 132 133 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 134 fe->dpcm[stream].runtime = fe_substream->runtime; 135 136 ret = dpcm_path_get(fe, stream, &list); 137 if (ret < 0) 138 goto be_err; 139 else if (ret == 0) 140 dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n", 141 fe->dai_link->name, stream ? "capture" : "playback"); 142 /* calculate valid and active FE <-> BE dpcms */ 143 dpcm_process_paths(fe, stream, &list, 1); 144 fe->dpcm[stream].runtime = fe_substream->runtime; 145 146 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 147 148 ret = dpcm_be_dai_startup(fe, stream); 149 if (ret < 0) { 150 /* clean up all links */ 151 for_each_dpcm_be(fe, stream, dpcm) 152 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; 153 154 dpcm_be_disconnect(fe, stream); 155 fe->dpcm[stream].runtime = NULL; 156 goto out; 157 } 158 159 ret = snd_soc_dai_compr_startup(cpu_dai, cstream); 160 if (ret < 0) 161 goto out; 162 163 ret = soc_compr_components_open(cstream, &component); 164 if (ret < 0) 165 goto open_err; 166 167 ret = snd_soc_link_compr_startup(cstream); 168 if (ret < 0) 169 goto machine_err; 170 171 dpcm_clear_pending_state(fe, stream); 172 dpcm_path_put(&list); 173 174 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; 175 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 176 177 snd_soc_runtime_activate(fe, stream); 178 179 mutex_unlock(&fe->card->mutex); 180 181 return 0; 182 183machine_err: 184 soc_compr_components_free(cstream, component); 185open_err: 186 snd_soc_dai_compr_shutdown(cpu_dai, cstream); 187out: 188 dpcm_path_put(&list); 189be_err: 190 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 191 mutex_unlock(&fe->card->mutex); 192 return ret; 193} 194 195static int soc_compr_free(struct snd_compr_stream *cstream) 196{ 197 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 198 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 199 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 200 int stream; 201 202 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 203 204 if (cstream->direction == SND_COMPRESS_PLAYBACK) 205 stream = SNDRV_PCM_STREAM_PLAYBACK; 206 else 207 stream = SNDRV_PCM_STREAM_CAPTURE; 208 209 snd_soc_runtime_deactivate(rtd, stream); 210 211 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); 212 213 if (!snd_soc_dai_active(cpu_dai)) 214 cpu_dai->rate = 0; 215 216 if (!snd_soc_dai_active(codec_dai)) 217 codec_dai->rate = 0; 218 219 snd_soc_link_compr_shutdown(cstream); 220 221 soc_compr_components_free(cstream, NULL); 222 223 snd_soc_dai_compr_shutdown(cpu_dai, cstream); 224 225 snd_soc_dapm_stream_stop(rtd, stream); 226 227 mutex_unlock(&rtd->card->pcm_mutex); 228 229 snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 0); 230 231 return 0; 232} 233 234static int soc_compr_free_fe(struct snd_compr_stream *cstream) 235{ 236 struct snd_soc_pcm_runtime *fe = cstream->private_data; 237 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 238 struct snd_soc_dpcm *dpcm; 239 int stream, ret; 240 241 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 242 243 if (cstream->direction == SND_COMPRESS_PLAYBACK) 244 stream = SNDRV_PCM_STREAM_PLAYBACK; 245 else 246 stream = SNDRV_PCM_STREAM_CAPTURE; 247 248 snd_soc_runtime_deactivate(fe, stream); 249 250 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 251 252 ret = dpcm_be_dai_hw_free(fe, stream); 253 if (ret < 0) 254 dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret); 255 256 ret = dpcm_be_dai_shutdown(fe, stream); 257 258 /* mark FE's links ready to prune */ 259 for_each_dpcm_be(fe, stream, dpcm) 260 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; 261 262 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); 263 264 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; 265 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 266 267 dpcm_be_disconnect(fe, stream); 268 269 fe->dpcm[stream].runtime = NULL; 270 271 snd_soc_link_compr_shutdown(cstream); 272 273 soc_compr_components_free(cstream, NULL); 274 275 snd_soc_dai_compr_shutdown(cpu_dai, cstream); 276 277 mutex_unlock(&fe->card->mutex); 278 return 0; 279} 280 281static int soc_compr_components_trigger(struct snd_compr_stream *cstream, 282 int cmd) 283{ 284 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 285 struct snd_soc_component *component; 286 int i, ret; 287 288 for_each_rtd_components(rtd, i, component) { 289 if (!component->driver->compress_ops || 290 !component->driver->compress_ops->trigger) 291 continue; 292 293 ret = component->driver->compress_ops->trigger( 294 component, cstream, cmd); 295 if (ret < 0) 296 return ret; 297 } 298 299 return 0; 300} 301 302static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) 303{ 304 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 305 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 306 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 307 int ret; 308 309 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 310 311 ret = soc_compr_components_trigger(cstream, cmd); 312 if (ret < 0) 313 goto out; 314 315 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); 316 if (ret < 0) 317 goto out; 318 319 switch (cmd) { 320 case SNDRV_PCM_TRIGGER_START: 321 snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction); 322 break; 323 case SNDRV_PCM_TRIGGER_STOP: 324 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); 325 break; 326 } 327 328out: 329 mutex_unlock(&rtd->card->pcm_mutex); 330 return ret; 331} 332 333static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) 334{ 335 struct snd_soc_pcm_runtime *fe = cstream->private_data; 336 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 337 int ret, stream; 338 339 if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || 340 cmd == SND_COMPR_TRIGGER_DRAIN) 341 return soc_compr_components_trigger(cstream, cmd); 342 343 if (cstream->direction == SND_COMPRESS_PLAYBACK) 344 stream = SNDRV_PCM_STREAM_PLAYBACK; 345 else 346 stream = SNDRV_PCM_STREAM_CAPTURE; 347 348 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 349 350 ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); 351 if (ret < 0) 352 goto out; 353 354 ret = soc_compr_components_trigger(cstream, cmd); 355 if (ret < 0) 356 goto out; 357 358 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 359 360 ret = dpcm_be_dai_trigger(fe, stream, cmd); 361 362 switch (cmd) { 363 case SNDRV_PCM_TRIGGER_START: 364 case SNDRV_PCM_TRIGGER_RESUME: 365 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 366 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START; 367 break; 368 case SNDRV_PCM_TRIGGER_STOP: 369 case SNDRV_PCM_TRIGGER_SUSPEND: 370 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; 371 break; 372 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 373 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; 374 break; 375 } 376 377out: 378 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 379 mutex_unlock(&fe->card->mutex); 380 return ret; 381} 382 383static int soc_compr_components_set_params(struct snd_compr_stream *cstream, 384 struct snd_compr_params *params) 385{ 386 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 387 struct snd_soc_component *component; 388 int i, ret; 389 390 for_each_rtd_components(rtd, i, component) { 391 if (!component->driver->compress_ops || 392 !component->driver->compress_ops->set_params) 393 continue; 394 395 ret = component->driver->compress_ops->set_params( 396 component, cstream, params); 397 if (ret < 0) 398 return ret; 399 } 400 401 return 0; 402} 403 404static int soc_compr_set_params(struct snd_compr_stream *cstream, 405 struct snd_compr_params *params) 406{ 407 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 408 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 409 int ret; 410 411 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 412 413 /* 414 * First we call set_params for the CPU DAI, then the component 415 * driver this should configure the SoC side. If the machine has 416 * compressed ops then we call that as well. The expectation is 417 * that these callbacks will configure everything for this compress 418 * path, like configuring a PCM port for a CODEC. 419 */ 420 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params); 421 if (ret < 0) 422 goto err; 423 424 ret = soc_compr_components_set_params(cstream, params); 425 if (ret < 0) 426 goto err; 427 428 ret = snd_soc_link_compr_set_params(cstream); 429 if (ret < 0) 430 goto err; 431 432 if (cstream->direction == SND_COMPRESS_PLAYBACK) 433 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, 434 SND_SOC_DAPM_STREAM_START); 435 else 436 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, 437 SND_SOC_DAPM_STREAM_START); 438 439 /* cancel any delayed stream shutdown that is pending */ 440 rtd->pop_wait = 0; 441 mutex_unlock(&rtd->card->pcm_mutex); 442 443 cancel_delayed_work_sync(&rtd->delayed_work); 444 445 return 0; 446 447err: 448 mutex_unlock(&rtd->card->pcm_mutex); 449 return ret; 450} 451 452static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, 453 struct snd_compr_params *params) 454{ 455 struct snd_soc_pcm_runtime *fe = cstream->private_data; 456 struct snd_pcm_substream *fe_substream = 457 fe->pcm->streams[cstream->direction].substream; 458 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); 459 int ret, stream; 460 461 if (cstream->direction == SND_COMPRESS_PLAYBACK) 462 stream = SNDRV_PCM_STREAM_PLAYBACK; 463 else 464 stream = SNDRV_PCM_STREAM_CAPTURE; 465 466 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 467 468 /* 469 * Create an empty hw_params for the BE as the machine driver must 470 * fix this up to match DSP decoder and ASRC configuration. 471 * I.e. machine driver fixup for compressed BE is mandatory. 472 */ 473 memset(&fe->dpcm[fe_substream->stream].hw_params, 0, 474 sizeof(struct snd_pcm_hw_params)); 475 476 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 477 478 ret = dpcm_be_dai_hw_params(fe, stream); 479 if (ret < 0) 480 goto out; 481 482 ret = dpcm_be_dai_prepare(fe, stream); 483 if (ret < 0) 484 goto out; 485 486 ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params); 487 if (ret < 0) 488 goto out; 489 490 ret = soc_compr_components_set_params(cstream, params); 491 if (ret < 0) 492 goto out; 493 494 ret = snd_soc_link_compr_set_params(cstream); 495 if (ret < 0) 496 goto out; 497 498 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); 499 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; 500 501out: 502 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 503 mutex_unlock(&fe->card->mutex); 504 return ret; 505} 506 507static int soc_compr_get_params(struct snd_compr_stream *cstream, 508 struct snd_codec *params) 509{ 510 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 511 struct snd_soc_component *component; 512 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 513 int i, ret = 0; 514 515 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 516 517 ret = snd_soc_dai_compr_get_params(cpu_dai, cstream, params); 518 if (ret < 0) 519 goto err; 520 521 for_each_rtd_components(rtd, i, component) { 522 if (!component->driver->compress_ops || 523 !component->driver->compress_ops->get_params) 524 continue; 525 526 ret = component->driver->compress_ops->get_params( 527 component, cstream, params); 528 break; 529 } 530 531err: 532 mutex_unlock(&rtd->card->pcm_mutex); 533 return ret; 534} 535 536static int soc_compr_get_caps(struct snd_compr_stream *cstream, 537 struct snd_compr_caps *caps) 538{ 539 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 540 struct snd_soc_component *component; 541 int i, ret = 0; 542 543 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 544 545 for_each_rtd_components(rtd, i, component) { 546 if (!component->driver->compress_ops || 547 !component->driver->compress_ops->get_caps) 548 continue; 549 550 ret = component->driver->compress_ops->get_caps( 551 component, cstream, caps); 552 break; 553 } 554 555 mutex_unlock(&rtd->card->pcm_mutex); 556 return ret; 557} 558 559static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, 560 struct snd_compr_codec_caps *codec) 561{ 562 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 563 struct snd_soc_component *component; 564 int i, ret = 0; 565 566 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 567 568 for_each_rtd_components(rtd, i, component) { 569 if (!component->driver->compress_ops || 570 !component->driver->compress_ops->get_codec_caps) 571 continue; 572 573 ret = component->driver->compress_ops->get_codec_caps( 574 component, cstream, codec); 575 break; 576 } 577 578 mutex_unlock(&rtd->card->pcm_mutex); 579 return ret; 580} 581 582static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) 583{ 584 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 585 struct snd_soc_component *component; 586 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 587 int i, ret = 0; 588 589 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 590 591 ret = snd_soc_dai_compr_ack(cpu_dai, cstream, bytes); 592 if (ret < 0) 593 goto err; 594 595 for_each_rtd_components(rtd, i, component) { 596 if (!component->driver->compress_ops || 597 !component->driver->compress_ops->ack) 598 continue; 599 600 ret = component->driver->compress_ops->ack( 601 component, cstream, bytes); 602 if (ret < 0) 603 goto err; 604 } 605 606err: 607 mutex_unlock(&rtd->card->pcm_mutex); 608 return ret; 609} 610 611static int soc_compr_pointer(struct snd_compr_stream *cstream, 612 struct snd_compr_tstamp *tstamp) 613{ 614 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 615 struct snd_soc_component *component; 616 int i, ret = 0; 617 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 618 619 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 620 621 ret = snd_soc_dai_compr_pointer(cpu_dai, cstream, tstamp); 622 if (ret < 0) 623 goto out; 624 625 for_each_rtd_components(rtd, i, component) { 626 if (!component->driver->compress_ops || 627 !component->driver->compress_ops->pointer) 628 continue; 629 630 ret = component->driver->compress_ops->pointer( 631 component, cstream, tstamp); 632 break; 633 } 634out: 635 mutex_unlock(&rtd->card->pcm_mutex); 636 return ret; 637} 638 639static int soc_compr_copy(struct snd_compr_stream *cstream, 640 char __user *buf, size_t count) 641{ 642 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 643 struct snd_soc_component *component; 644 int i, ret = 0; 645 646 mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); 647 648 for_each_rtd_components(rtd, i, component) { 649 if (!component->driver->compress_ops || 650 !component->driver->compress_ops->copy) 651 continue; 652 653 ret = component->driver->compress_ops->copy( 654 component, cstream, buf, count); 655 break; 656 } 657 658 mutex_unlock(&rtd->card->pcm_mutex); 659 return ret; 660} 661 662static int soc_compr_set_metadata(struct snd_compr_stream *cstream, 663 struct snd_compr_metadata *metadata) 664{ 665 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 666 struct snd_soc_component *component; 667 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 668 int i, ret; 669 670 ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata); 671 if (ret < 0) 672 return ret; 673 674 for_each_rtd_components(rtd, i, component) { 675 if (!component->driver->compress_ops || 676 !component->driver->compress_ops->set_metadata) 677 continue; 678 679 ret = component->driver->compress_ops->set_metadata( 680 component, cstream, metadata); 681 if (ret < 0) 682 return ret; 683 } 684 685 return 0; 686} 687 688static int soc_compr_get_metadata(struct snd_compr_stream *cstream, 689 struct snd_compr_metadata *metadata) 690{ 691 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 692 struct snd_soc_component *component; 693 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 694 int i, ret; 695 696 ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata); 697 if (ret < 0) 698 return ret; 699 700 for_each_rtd_components(rtd, i, component) { 701 if (!component->driver->compress_ops || 702 !component->driver->compress_ops->get_metadata) 703 continue; 704 705 return component->driver->compress_ops->get_metadata( 706 component, cstream, metadata); 707 } 708 709 return 0; 710} 711 712/* ASoC Compress operations */ 713static struct snd_compr_ops soc_compr_ops = { 714 .open = soc_compr_open, 715 .free = soc_compr_free, 716 .set_params = soc_compr_set_params, 717 .set_metadata = soc_compr_set_metadata, 718 .get_metadata = soc_compr_get_metadata, 719 .get_params = soc_compr_get_params, 720 .trigger = soc_compr_trigger, 721 .pointer = soc_compr_pointer, 722 .ack = soc_compr_ack, 723 .get_caps = soc_compr_get_caps, 724 .get_codec_caps = soc_compr_get_codec_caps 725}; 726 727/* ASoC Dynamic Compress operations */ 728static struct snd_compr_ops soc_compr_dyn_ops = { 729 .open = soc_compr_open_fe, 730 .free = soc_compr_free_fe, 731 .set_params = soc_compr_set_params_fe, 732 .get_params = soc_compr_get_params, 733 .set_metadata = soc_compr_set_metadata, 734 .get_metadata = soc_compr_get_metadata, 735 .trigger = soc_compr_trigger_fe, 736 .pointer = soc_compr_pointer, 737 .ack = soc_compr_ack, 738 .get_caps = soc_compr_get_caps, 739 .get_codec_caps = soc_compr_get_codec_caps 740}; 741 742/** 743 * snd_soc_new_compress - create a new compress. 744 * 745 * @rtd: The runtime for which we will create compress 746 * @num: the device index number (zero based - shared with normal PCMs) 747 * 748 * Return: 0 for success, else error. 749 */ 750int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) 751{ 752 struct snd_soc_component *component; 753 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 754 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 755 struct snd_compr *compr; 756 struct snd_pcm *be_pcm; 757 char new_name[64]; 758 int ret = 0, direction = 0; 759 int playback = 0, capture = 0; 760 int i; 761 762 if (rtd->num_cpus > 1 || 763 rtd->num_codecs > 1) { 764 dev_err(rtd->card->dev, 765 "Compress ASoC: Multi CPU/Codec not supported\n"); 766 return -EINVAL; 767 } 768 769 if (!codec_dai) { 770 dev_err(rtd->card->dev, "Missing codec\n"); 771 return -EINVAL; 772 } 773 774 /* check client and interface hw capabilities */ 775 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && 776 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) 777 playback = 1; 778 if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && 779 snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) 780 capture = 1; 781 782 /* 783 * Compress devices are unidirectional so only one of the directions 784 * should be set, check for that (xor) 785 */ 786 if (playback + capture != 1) { 787 dev_err(rtd->card->dev, 788 "Compress ASoC: Invalid direction for P %d, C %d\n", 789 playback, capture); 790 return -EINVAL; 791 } 792 793 if (playback) 794 direction = SND_COMPRESS_PLAYBACK; 795 else 796 direction = SND_COMPRESS_CAPTURE; 797 798 compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL); 799 if (!compr) 800 return -ENOMEM; 801 802 compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops), 803 GFP_KERNEL); 804 if (!compr->ops) 805 return -ENOMEM; 806 807 if (rtd->dai_link->dynamic) { 808 snprintf(new_name, sizeof(new_name), "(%s)", 809 rtd->dai_link->stream_name); 810 811 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, 812 rtd->dai_link->dpcm_playback, 813 rtd->dai_link->dpcm_capture, &be_pcm); 814 if (ret < 0) { 815 dev_err(rtd->card->dev, 816 "Compress ASoC: can't create compressed for %s: %d\n", 817 rtd->dai_link->name, ret); 818 return ret; 819 } 820 821 rtd->pcm = be_pcm; 822 rtd->fe_compr = 1; 823 if (rtd->dai_link->dpcm_playback) 824 be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; 825 if (rtd->dai_link->dpcm_capture) 826 be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; 827 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops)); 828 } else { 829 snprintf(new_name, sizeof(new_name), "%s %s-%d", 830 rtd->dai_link->stream_name, codec_dai->name, num); 831 832 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); 833 } 834 835 for_each_rtd_components(rtd, i, component) { 836 if (!component->driver->compress_ops || 837 !component->driver->compress_ops->copy) 838 continue; 839 840 compr->ops->copy = soc_compr_copy; 841 break; 842 } 843 844 mutex_init(&compr->lock); 845 ret = snd_compress_new(rtd->card->snd_card, num, direction, 846 new_name, compr); 847 if (ret < 0) { 848 component = asoc_rtd_to_codec(rtd, 0)->component; 849 dev_err(component->dev, 850 "Compress ASoC: can't create compress for codec %s: %d\n", 851 component->name, ret); 852 return ret; 853 } 854 855 /* DAPM dai link stream work */ 856 rtd->close_delayed_work_func = snd_soc_close_delayed_work; 857 858 rtd->compr = compr; 859 compr->private_data = rtd; 860 861 dev_dbg(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n", 862 codec_dai->name, cpu_dai->name); 863 864 return 0; 865} 866EXPORT_SYMBOL_GPL(snd_soc_new_compress); 867