root/sound/core/pcm_timer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_pcm_timer_resolution_change
  2. snd_pcm_timer_resolution
  3. snd_pcm_timer_start
  4. snd_pcm_timer_stop
  5. snd_pcm_timer_free
  6. snd_pcm_timer_init
  7. snd_pcm_timer_done

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Digital Audio (PCM) abstract layer
   4  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   5  */
   6 
   7 #include <linux/time.h>
   8 #include <linux/gcd.h>
   9 #include <sound/core.h>
  10 #include <sound/pcm.h>
  11 #include <sound/timer.h>
  12 
  13 #include "pcm_local.h"
  14 
  15 /*
  16  *  Timer functions
  17  */
  18 
  19 void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
  20 {
  21         unsigned long rate, mult, fsize, l, post;
  22         struct snd_pcm_runtime *runtime = substream->runtime;
  23 
  24         mult = 1000000000;
  25         rate = runtime->rate;
  26         if (snd_BUG_ON(!rate))
  27                 return;
  28         l = gcd(mult, rate);
  29         mult /= l;
  30         rate /= l;
  31         fsize = runtime->period_size;
  32         if (snd_BUG_ON(!fsize))
  33                 return;
  34         l = gcd(rate, fsize);
  35         rate /= l;
  36         fsize /= l;
  37         post = 1;
  38         while ((mult * fsize) / fsize != mult) {
  39                 mult /= 2;
  40                 post *= 2;
  41         }
  42         if (rate == 0) {
  43                 pcm_err(substream->pcm,
  44                         "pcm timer resolution out of range (rate = %u, period_size = %lu)\n",
  45                         runtime->rate, runtime->period_size);
  46                 runtime->timer_resolution = -1;
  47                 return;
  48         }
  49         runtime->timer_resolution = (mult * fsize / rate) * post;
  50 }
  51 
  52 static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
  53 {
  54         struct snd_pcm_substream *substream;
  55 
  56         substream = timer->private_data;
  57         return substream->runtime ? substream->runtime->timer_resolution : 0;
  58 }
  59 
  60 static int snd_pcm_timer_start(struct snd_timer * timer)
  61 {
  62         struct snd_pcm_substream *substream;
  63 
  64         substream = snd_timer_chip(timer);
  65         substream->timer_running = 1;
  66         return 0;
  67 }
  68 
  69 static int snd_pcm_timer_stop(struct snd_timer * timer)
  70 {
  71         struct snd_pcm_substream *substream;
  72 
  73         substream = snd_timer_chip(timer);
  74         substream->timer_running = 0;
  75         return 0;
  76 }
  77 
  78 static struct snd_timer_hardware snd_pcm_timer =
  79 {
  80         .flags =        SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE,
  81         .resolution =   0,
  82         .ticks =        1,
  83         .c_resolution = snd_pcm_timer_resolution,
  84         .start =        snd_pcm_timer_start,
  85         .stop =         snd_pcm_timer_stop,
  86 };
  87 
  88 /*
  89  *  Init functions
  90  */
  91 
  92 static void snd_pcm_timer_free(struct snd_timer *timer)
  93 {
  94         struct snd_pcm_substream *substream = timer->private_data;
  95         substream->timer = NULL;
  96 }
  97 
  98 void snd_pcm_timer_init(struct snd_pcm_substream *substream)
  99 {
 100         struct snd_timer_id tid;
 101         struct snd_timer *timer;
 102 
 103         tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
 104         tid.dev_class = SNDRV_TIMER_CLASS_PCM;
 105         tid.card = substream->pcm->card->number;
 106         tid.device = substream->pcm->device;
 107         tid.subdevice = (substream->number << 1) | (substream->stream & 1);
 108         if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0)
 109                 return;
 110         sprintf(timer->name, "PCM %s %i-%i-%i",
 111                         substream->stream == SNDRV_PCM_STREAM_CAPTURE ?
 112                                 "capture" : "playback",
 113                         tid.card, tid.device, tid.subdevice);
 114         timer->hw = snd_pcm_timer;
 115         if (snd_device_register(timer->card, timer) < 0) {
 116                 snd_device_free(timer->card, timer);
 117                 return;
 118         }
 119         timer->private_data = substream;
 120         timer->private_free = snd_pcm_timer_free;
 121         substream->timer = timer;
 122 }
 123 
 124 void snd_pcm_timer_done(struct snd_pcm_substream *substream)
 125 {
 126         if (substream->timer) {
 127                 snd_device_free(substream->pcm->card, substream->timer);
 128                 substream->timer = NULL;
 129         }
 130 }

/* [<][>][^][v][top][bottom][index][help] */