Version:  2.0.40 2.2.26 2.4.37 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10

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

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