Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

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

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