Version:  2.0.40 2.2.26 2.4.37 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2

Linux/sound/soc/soc-compress.c

  1 /*
  2  * soc-compress.c  --  ALSA SoC Compress
  3  *
  4  * Copyright (C) 2012 Intel Corp.
  5  *
  6  * Authors: Namarta Kohli <namartax.kohli@intel.com>
  7  *          Ramesh Babu K V <ramesh.babu@linux.intel.com>
  8  *          Vinod Koul <vinod.koul@linux.intel.com>
  9  *
 10  *  This program is free software; you can redistribute  it and/or modify it
 11  *  under  the terms of  the GNU General  Public License as published by the
 12  *  Free Software Foundation;  either version 2 of the  License, or (at your
 13  *  option) any later version.
 14  *
 15  */
 16 
 17 #include <linux/kernel.h>
 18 #include <linux/init.h>
 19 #include <linux/delay.h>
 20 #include <linux/slab.h>
 21 #include <linux/workqueue.h>
 22 #include <sound/core.h>
 23 #include <sound/compress_params.h>
 24 #include <sound/compress_driver.h>
 25 #include <sound/soc.h>
 26 #include <sound/initval.h>
 27 #include <sound/soc-dpcm.h>
 28 
 29 static int soc_compr_open(struct snd_compr_stream *cstream)
 30 {
 31         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 32         struct snd_soc_platform *platform = rtd->platform;
 33         int ret = 0;
 34 
 35         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 36 
 37         if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
 38                 ret = platform->driver->compr_ops->open(cstream);
 39                 if (ret < 0) {
 40                         pr_err("compress asoc: can't open platform %s\n",
 41                                 platform->component.name);
 42                         goto out;
 43                 }
 44         }
 45 
 46         if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
 47                 ret = rtd->dai_link->compr_ops->startup(cstream);
 48                 if (ret < 0) {
 49                         pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
 50                         goto machine_err;
 51                 }
 52         }
 53 
 54         snd_soc_runtime_activate(rtd, cstream->direction);
 55 
 56         mutex_unlock(&rtd->pcm_mutex);
 57 
 58         return 0;
 59 
 60 machine_err:
 61         if (platform->driver->compr_ops && platform->driver->compr_ops->free)
 62                 platform->driver->compr_ops->free(cstream);
 63 out:
 64         mutex_unlock(&rtd->pcm_mutex);
 65         return ret;
 66 }
 67 
 68 static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 69 {
 70         struct snd_soc_pcm_runtime *fe = cstream->private_data;
 71         struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
 72         struct snd_soc_platform *platform = fe->platform;
 73         struct snd_soc_dpcm *dpcm;
 74         struct snd_soc_dapm_widget_list *list;
 75         int stream;
 76         int ret = 0;
 77 
 78         if (cstream->direction == SND_COMPRESS_PLAYBACK)
 79                 stream = SNDRV_PCM_STREAM_PLAYBACK;
 80         else
 81                 stream = SNDRV_PCM_STREAM_CAPTURE;
 82 
 83         mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 84 
 85         if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
 86                 ret = platform->driver->compr_ops->open(cstream);
 87                 if (ret < 0) {
 88                         pr_err("compress asoc: can't open platform %s\n",
 89                                 platform->component.name);
 90                         goto out;
 91                 }
 92         }
 93 
 94         if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
 95                 ret = fe->dai_link->compr_ops->startup(cstream);
 96                 if (ret < 0) {
 97                         pr_err("compress asoc: %s startup failed\n", fe->dai_link->name);
 98                         goto machine_err;
 99                 }
100         }
101 
102         fe->dpcm[stream].runtime = fe_substream->runtime;
103 
104         ret = dpcm_path_get(fe, stream, &list);
105         if (ret < 0)
106                 goto fe_err;
107         else if (ret == 0)
108                 dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
109                         fe->dai_link->name, stream ? "capture" : "playback");
110 
111         /* calculate valid and active FE <-> BE dpcms */
112         dpcm_process_paths(fe, stream, &list, 1);
113 
114         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
115 
116         ret = dpcm_be_dai_startup(fe, stream);
117         if (ret < 0) {
118                 /* clean up all links */
119                 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
120                         dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
121 
122                 dpcm_be_disconnect(fe, stream);
123                 fe->dpcm[stream].runtime = NULL;
124                 goto fe_err;
125         }
126 
127         dpcm_clear_pending_state(fe, stream);
128         dpcm_path_put(&list);
129 
130         fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
131         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
132 
133         snd_soc_runtime_activate(fe, stream);
134 
135         mutex_unlock(&fe->card->mutex);
136 
137         return 0;
138 
139 fe_err:
140         if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
141                 fe->dai_link->compr_ops->shutdown(cstream);
142 machine_err:
143         if (platform->driver->compr_ops && platform->driver->compr_ops->free)
144                 platform->driver->compr_ops->free(cstream);
145 out:
146         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
147         mutex_unlock(&fe->card->mutex);
148         return ret;
149 }
150 
151 /*
152  * Power down the audio subsystem pmdown_time msecs after close is called.
153  * This is to ensure there are no pops or clicks in between any music tracks
154  * due to DAPM power cycling.
155  */
156 static void close_delayed_work(struct work_struct *work)
157 {
158         struct snd_soc_pcm_runtime *rtd =
159                         container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
160         struct snd_soc_dai *codec_dai = rtd->codec_dai;
161 
162         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
163 
164         dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
165                  codec_dai->driver->playback.stream_name,
166                  codec_dai->playback_active ? "active" : "inactive",
167                  rtd->pop_wait ? "yes" : "no");
168 
169         /* are we waiting on this codec DAI stream */
170         if (rtd->pop_wait == 1) {
171                 rtd->pop_wait = 0;
172                 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
173                                           SND_SOC_DAPM_STREAM_STOP);
174         }
175 
176         mutex_unlock(&rtd->pcm_mutex);
177 }
178 
179 static int soc_compr_free(struct snd_compr_stream *cstream)
180 {
181         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
182         struct snd_soc_platform *platform = rtd->platform;
183         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
184         struct snd_soc_dai *codec_dai = rtd->codec_dai;
185         int stream;
186 
187         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
188 
189         if (cstream->direction == SND_COMPRESS_PLAYBACK)
190                 stream = SNDRV_PCM_STREAM_PLAYBACK;
191         else
192                 stream = SNDRV_PCM_STREAM_CAPTURE;
193 
194         snd_soc_runtime_deactivate(rtd, stream);
195 
196         snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
197 
198         if (!cpu_dai->active)
199                 cpu_dai->rate = 0;
200 
201         if (!codec_dai->active)
202                 codec_dai->rate = 0;
203 
204 
205         if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
206                 rtd->dai_link->compr_ops->shutdown(cstream);
207 
208         if (platform->driver->compr_ops && platform->driver->compr_ops->free)
209                 platform->driver->compr_ops->free(cstream);
210 
211         if (cstream->direction == SND_COMPRESS_PLAYBACK) {
212                 if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
213                         snd_soc_dapm_stream_event(rtd,
214                                         SNDRV_PCM_STREAM_PLAYBACK,
215                                         SND_SOC_DAPM_STREAM_STOP);
216                 } else {
217                         rtd->pop_wait = 1;
218                         queue_delayed_work(system_power_efficient_wq,
219                                            &rtd->delayed_work,
220                                            msecs_to_jiffies(rtd->pmdown_time));
221                 }
222         } else {
223                 /* capture streams can be powered down now */
224                 snd_soc_dapm_stream_event(rtd,
225                         SNDRV_PCM_STREAM_CAPTURE,
226                         SND_SOC_DAPM_STREAM_STOP);
227         }
228 
229         mutex_unlock(&rtd->pcm_mutex);
230         return 0;
231 }
232 
233 static int soc_compr_free_fe(struct snd_compr_stream *cstream)
234 {
235         struct snd_soc_pcm_runtime *fe = cstream->private_data;
236         struct snd_soc_platform *platform = fe->platform;
237         struct snd_soc_dpcm *dpcm;
238         int stream, ret;
239 
240         mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
241 
242         if (cstream->direction == SND_COMPRESS_PLAYBACK)
243                 stream = SNDRV_PCM_STREAM_PLAYBACK;
244         else
245                 stream = SNDRV_PCM_STREAM_CAPTURE;
246 
247         snd_soc_runtime_deactivate(fe, stream);
248 
249         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
250 
251         ret = dpcm_be_dai_hw_free(fe, stream);
252         if (ret < 0)
253                 dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
254 
255         ret = dpcm_be_dai_shutdown(fe, stream);
256 
257         /* mark FE's links ready to prune */
258         list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
259                 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
260 
261         dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
262 
263         fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
264         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
265 
266         dpcm_be_disconnect(fe, stream);
267 
268         fe->dpcm[stream].runtime = NULL;
269 
270         if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
271                 fe->dai_link->compr_ops->shutdown(cstream);
272 
273         if (platform->driver->compr_ops && platform->driver->compr_ops->free)
274                 platform->driver->compr_ops->free(cstream);
275 
276         mutex_unlock(&fe->card->mutex);
277         return 0;
278 }
279 
280 static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
281 {
282 
283         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
284         struct snd_soc_platform *platform = rtd->platform;
285         struct snd_soc_dai *codec_dai = rtd->codec_dai;
286         int ret = 0;
287 
288         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
289 
290         if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
291                 ret = platform->driver->compr_ops->trigger(cstream, cmd);
292                 if (ret < 0)
293                         goto out;
294         }
295 
296         switch (cmd) {
297         case SNDRV_PCM_TRIGGER_START:
298                 snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
299                 break;
300         case SNDRV_PCM_TRIGGER_STOP:
301                 snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
302                 break;
303         }
304 
305 out:
306         mutex_unlock(&rtd->pcm_mutex);
307         return ret;
308 }
309 
310 static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
311 {
312         struct snd_soc_pcm_runtime *fe = cstream->private_data;
313         struct snd_soc_platform *platform = fe->platform;
314         int ret = 0, stream;
315 
316         if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
317                 cmd == SND_COMPR_TRIGGER_DRAIN) {
318 
319                 if (platform->driver->compr_ops &&
320                     platform->driver->compr_ops->trigger)
321                         return platform->driver->compr_ops->trigger(cstream,
322                                                                     cmd);
323         }
324 
325         if (cstream->direction == SND_COMPRESS_PLAYBACK)
326                 stream = SNDRV_PCM_STREAM_PLAYBACK;
327         else
328                 stream = SNDRV_PCM_STREAM_CAPTURE;
329 
330 
331         mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
332 
333         if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
334                 ret = platform->driver->compr_ops->trigger(cstream, cmd);
335                 if (ret < 0)
336                         goto out;
337         }
338 
339         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
340 
341         ret = dpcm_be_dai_trigger(fe, stream, cmd);
342 
343         switch (cmd) {
344         case SNDRV_PCM_TRIGGER_START:
345         case SNDRV_PCM_TRIGGER_RESUME:
346         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
347                 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
348                 break;
349         case SNDRV_PCM_TRIGGER_STOP:
350         case SNDRV_PCM_TRIGGER_SUSPEND:
351                 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
352                 break;
353         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
354                 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
355                 break;
356         }
357 
358 out:
359         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
360         mutex_unlock(&fe->card->mutex);
361         return ret;
362 }
363 
364 static int soc_compr_set_params(struct snd_compr_stream *cstream,
365                                         struct snd_compr_params *params)
366 {
367         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
368         struct snd_soc_platform *platform = rtd->platform;
369         int ret = 0;
370 
371         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
372 
373         /* first we call set_params for the platform driver
374          * this should configure the soc side
375          * if the machine has compressed ops then we call that as well
376          * expectation is that platform and machine will configure everything
377          * for this compress path, like configuring pcm port for codec
378          */
379         if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
380                 ret = platform->driver->compr_ops->set_params(cstream, params);
381                 if (ret < 0)
382                         goto err;
383         }
384 
385         if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
386                 ret = rtd->dai_link->compr_ops->set_params(cstream);
387                 if (ret < 0)
388                         goto err;
389         }
390 
391         if (cstream->direction == SND_COMPRESS_PLAYBACK)
392                 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
393                                         SND_SOC_DAPM_STREAM_START);
394         else
395                 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
396                                         SND_SOC_DAPM_STREAM_START);
397 
398         /* cancel any delayed stream shutdown that is pending */
399         rtd->pop_wait = 0;
400         mutex_unlock(&rtd->pcm_mutex);
401 
402         cancel_delayed_work_sync(&rtd->delayed_work);
403 
404         return ret;
405 
406 err:
407         mutex_unlock(&rtd->pcm_mutex);
408         return ret;
409 }
410 
411 static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
412                                         struct snd_compr_params *params)
413 {
414         struct snd_soc_pcm_runtime *fe = cstream->private_data;
415         struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
416         struct snd_soc_platform *platform = fe->platform;
417         int ret = 0, stream;
418 
419         if (cstream->direction == SND_COMPRESS_PLAYBACK)
420                 stream = SNDRV_PCM_STREAM_PLAYBACK;
421         else
422                 stream = SNDRV_PCM_STREAM_CAPTURE;
423 
424         mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
425 
426         if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
427                 ret = platform->driver->compr_ops->set_params(cstream, params);
428                 if (ret < 0)
429                         goto out;
430         }
431 
432         if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
433                 ret = fe->dai_link->compr_ops->set_params(cstream);
434                 if (ret < 0)
435                         goto out;
436         }
437 
438         /*
439          * Create an empty hw_params for the BE as the machine driver must
440          * fix this up to match DSP decoder and ASRC configuration.
441          * I.e. machine driver fixup for compressed BE is mandatory.
442          */
443         memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
444                 sizeof(struct snd_pcm_hw_params));
445 
446         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
447 
448         ret = dpcm_be_dai_hw_params(fe, stream);
449         if (ret < 0)
450                 goto out;
451 
452         ret = dpcm_be_dai_prepare(fe, stream);
453         if (ret < 0)
454                 goto out;
455 
456         dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
457         fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
458 
459 out:
460         fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
461         mutex_unlock(&fe->card->mutex);
462         return ret;
463 }
464 
465 static int soc_compr_get_params(struct snd_compr_stream *cstream,
466                                         struct snd_codec *params)
467 {
468         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
469         struct snd_soc_platform *platform = rtd->platform;
470         int ret = 0;
471 
472         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
473 
474         if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
475                 ret = platform->driver->compr_ops->get_params(cstream, params);
476 
477         mutex_unlock(&rtd->pcm_mutex);
478         return ret;
479 }
480 
481 static int soc_compr_get_caps(struct snd_compr_stream *cstream,
482                                 struct snd_compr_caps *caps)
483 {
484         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
485         struct snd_soc_platform *platform = rtd->platform;
486         int ret = 0;
487 
488         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
489 
490         if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
491                 ret = platform->driver->compr_ops->get_caps(cstream, caps);
492 
493         mutex_unlock(&rtd->pcm_mutex);
494         return ret;
495 }
496 
497 static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
498                                 struct snd_compr_codec_caps *codec)
499 {
500         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
501         struct snd_soc_platform *platform = rtd->platform;
502         int ret = 0;
503 
504         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
505 
506         if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
507                 ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
508 
509         mutex_unlock(&rtd->pcm_mutex);
510         return ret;
511 }
512 
513 static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
514 {
515         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
516         struct snd_soc_platform *platform = rtd->platform;
517         int ret = 0;
518 
519         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
520 
521         if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
522                 ret = platform->driver->compr_ops->ack(cstream, bytes);
523 
524         mutex_unlock(&rtd->pcm_mutex);
525         return ret;
526 }
527 
528 static int soc_compr_pointer(struct snd_compr_stream *cstream,
529                         struct snd_compr_tstamp *tstamp)
530 {
531         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
532         struct snd_soc_platform *platform = rtd->platform;
533 
534         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
535 
536         if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
537                  platform->driver->compr_ops->pointer(cstream, tstamp);
538 
539         mutex_unlock(&rtd->pcm_mutex);
540         return 0;
541 }
542 
543 static int soc_compr_copy(struct snd_compr_stream *cstream,
544                           char __user *buf, size_t count)
545 {
546         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
547         struct snd_soc_platform *platform = rtd->platform;
548         int ret = 0;
549 
550         mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
551 
552         if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
553                 ret = platform->driver->compr_ops->copy(cstream, buf, count);
554 
555         mutex_unlock(&rtd->pcm_mutex);
556         return ret;
557 }
558 
559 static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
560                                 struct snd_compr_metadata *metadata)
561 {
562         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
563         struct snd_soc_platform *platform = rtd->platform;
564         int ret = 0;
565 
566         if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
567                 ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
568 
569         return ret;
570 }
571 
572 static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
573                                 struct snd_compr_metadata *metadata)
574 {
575         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
576         struct snd_soc_platform *platform = rtd->platform;
577         int ret = 0;
578 
579         if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
580                 ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
581 
582         return ret;
583 }
584 
585 /* ASoC Compress operations */
586 static struct snd_compr_ops soc_compr_ops = {
587         .open           = soc_compr_open,
588         .free           = soc_compr_free,
589         .set_params     = soc_compr_set_params,
590         .set_metadata   = soc_compr_set_metadata,
591         .get_metadata   = soc_compr_get_metadata,
592         .get_params     = soc_compr_get_params,
593         .trigger        = soc_compr_trigger,
594         .pointer        = soc_compr_pointer,
595         .ack            = soc_compr_ack,
596         .get_caps       = soc_compr_get_caps,
597         .get_codec_caps = soc_compr_get_codec_caps
598 };
599 
600 /* ASoC Dynamic Compress operations */
601 static struct snd_compr_ops soc_compr_dyn_ops = {
602         .open           = soc_compr_open_fe,
603         .free           = soc_compr_free_fe,
604         .set_params     = soc_compr_set_params_fe,
605         .get_params     = soc_compr_get_params,
606         .set_metadata   = soc_compr_set_metadata,
607         .get_metadata   = soc_compr_get_metadata,
608         .trigger        = soc_compr_trigger_fe,
609         .pointer        = soc_compr_pointer,
610         .ack            = soc_compr_ack,
611         .get_caps       = soc_compr_get_caps,
612         .get_codec_caps = soc_compr_get_codec_caps
613 };
614 
615 /* create a new compress */
616 int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
617 {
618         struct snd_soc_codec *codec = rtd->codec;
619         struct snd_soc_platform *platform = rtd->platform;
620         struct snd_soc_dai *codec_dai = rtd->codec_dai;
621         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
622         struct snd_compr *compr;
623         struct snd_pcm *be_pcm;
624         char new_name[64];
625         int ret = 0, direction = 0;
626 
627         if (rtd->num_codecs > 1) {
628                 dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
629                 return -EINVAL;
630         }
631 
632         /* check client and interface hw capabilities */
633         snprintf(new_name, sizeof(new_name), "%s %s-%d",
634                         rtd->dai_link->stream_name, codec_dai->name, num);
635 
636         if (codec_dai->driver->playback.channels_min)
637                 direction = SND_COMPRESS_PLAYBACK;
638         else if (codec_dai->driver->capture.channels_min)
639                 direction = SND_COMPRESS_CAPTURE;
640         else
641                 return -EINVAL;
642 
643         compr = kzalloc(sizeof(*compr), GFP_KERNEL);
644         if (compr == NULL) {
645                 snd_printk(KERN_ERR "Cannot allocate compr\n");
646                 return -ENOMEM;
647         }
648 
649         compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
650                                   GFP_KERNEL);
651         if (compr->ops == NULL) {
652                 dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
653                 ret = -ENOMEM;
654                 goto compr_err;
655         }
656 
657         if (rtd->dai_link->dynamic) {
658                 snprintf(new_name, sizeof(new_name), "(%s)",
659                         rtd->dai_link->stream_name);
660 
661                 ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
662                                 rtd->dai_link->dpcm_playback,
663                                 rtd->dai_link->dpcm_capture, &be_pcm);
664                 if (ret < 0) {
665                         dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
666                                 rtd->dai_link->name);
667                         goto compr_err;
668                 }
669 
670                 rtd->pcm = be_pcm;
671                 rtd->fe_compr = 1;
672                 if (rtd->dai_link->dpcm_playback)
673                         be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
674                 else if (rtd->dai_link->dpcm_capture)
675                         be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
676                 memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
677         } else
678                 memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
679 
680         /* Add copy callback for not memory mapped DSPs */
681         if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
682                 compr->ops->copy = soc_compr_copy;
683 
684         mutex_init(&compr->lock);
685         ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
686         if (ret < 0) {
687                 pr_err("compress asoc: can't create compress for codec %s\n",
688                         codec->component.name);
689                 goto compr_err;
690         }
691 
692         /* DAPM dai link stream work */
693         INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
694 
695         rtd->compr = compr;
696         compr->private_data = rtd;
697 
698         printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
699                 cpu_dai->name);
700         return ret;
701 
702 compr_err:
703         kfree(compr);
704         return ret;
705 }
706 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us