root/sound/firewire/tascam/tascam-pcm.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcm_init_hw_params
  2. pcm_open
  3. pcm_close
  4. pcm_hw_params
  5. pcm_hw_free
  6. pcm_capture_prepare
  7. pcm_playback_prepare
  8. pcm_capture_trigger
  9. pcm_playback_trigger
  10. pcm_capture_pointer
  11. pcm_playback_pointer
  12. pcm_capture_ack
  13. pcm_playback_ack
  14. snd_tscm_create_pcm_devices

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * tascam-pcm.c - a part of driver for TASCAM FireWire series
   4  *
   5  * Copyright (c) 2015 Takashi Sakamoto
   6  */
   7 
   8 #include "tascam.h"
   9 
  10 static int pcm_init_hw_params(struct snd_tscm *tscm,
  11                               struct snd_pcm_substream *substream)
  12 {
  13         struct snd_pcm_runtime *runtime = substream->runtime;
  14         struct snd_pcm_hardware *hw = &runtime->hw;
  15         struct amdtp_stream *stream;
  16         unsigned int pcm_channels;
  17 
  18         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  19                 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
  20                 stream = &tscm->tx_stream;
  21                 pcm_channels = tscm->spec->pcm_capture_analog_channels;
  22         } else {
  23                 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
  24                 stream = &tscm->rx_stream;
  25                 pcm_channels = tscm->spec->pcm_playback_analog_channels;
  26         }
  27 
  28         if (tscm->spec->has_adat)
  29                 pcm_channels += 8;
  30         if (tscm->spec->has_spdif)
  31                 pcm_channels += 2;
  32         runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels;
  33 
  34         hw->rates = SNDRV_PCM_RATE_44100 |
  35                     SNDRV_PCM_RATE_48000 |
  36                     SNDRV_PCM_RATE_88200 |
  37                     SNDRV_PCM_RATE_96000;
  38         snd_pcm_limit_hw_rates(runtime);
  39 
  40         return amdtp_tscm_add_pcm_hw_constraints(stream, runtime);
  41 }
  42 
  43 static int pcm_open(struct snd_pcm_substream *substream)
  44 {
  45         struct snd_tscm *tscm = substream->private_data;
  46         enum snd_tscm_clock clock;
  47         unsigned int rate;
  48         int err;
  49 
  50         err = snd_tscm_stream_lock_try(tscm);
  51         if (err < 0)
  52                 goto end;
  53 
  54         err = pcm_init_hw_params(tscm, substream);
  55         if (err < 0)
  56                 goto err_locked;
  57 
  58         err = snd_tscm_stream_get_clock(tscm, &clock);
  59         if (err < 0)
  60                 goto err_locked;
  61 
  62         if (clock != SND_TSCM_CLOCK_INTERNAL ||
  63             amdtp_stream_pcm_running(&tscm->rx_stream) ||
  64             amdtp_stream_pcm_running(&tscm->tx_stream)) {
  65                 err = snd_tscm_stream_get_rate(tscm, &rate);
  66                 if (err < 0)
  67                         goto err_locked;
  68                 substream->runtime->hw.rate_min = rate;
  69                 substream->runtime->hw.rate_max = rate;
  70         }
  71 
  72         snd_pcm_set_sync(substream);
  73 end:
  74         return err;
  75 err_locked:
  76         snd_tscm_stream_lock_release(tscm);
  77         return err;
  78 }
  79 
  80 static int pcm_close(struct snd_pcm_substream *substream)
  81 {
  82         struct snd_tscm *tscm = substream->private_data;
  83 
  84         snd_tscm_stream_lock_release(tscm);
  85 
  86         return 0;
  87 }
  88 
  89 static int pcm_hw_params(struct snd_pcm_substream *substream,
  90                          struct snd_pcm_hw_params *hw_params)
  91 {
  92         struct snd_tscm *tscm = substream->private_data;
  93         int err;
  94 
  95         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
  96                                                params_buffer_bytes(hw_params));
  97         if (err < 0)
  98                 return err;
  99 
 100         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 101                 unsigned int rate = params_rate(hw_params);
 102 
 103                 mutex_lock(&tscm->mutex);
 104                 err = snd_tscm_stream_reserve_duplex(tscm, rate);
 105                 if (err >= 0)
 106                         ++tscm->substreams_counter;
 107                 mutex_unlock(&tscm->mutex);
 108         }
 109 
 110         return err;
 111 }
 112 
 113 static int pcm_hw_free(struct snd_pcm_substream *substream)
 114 {
 115         struct snd_tscm *tscm = substream->private_data;
 116 
 117         mutex_lock(&tscm->mutex);
 118 
 119         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 120                 --tscm->substreams_counter;
 121 
 122         snd_tscm_stream_stop_duplex(tscm);
 123 
 124         mutex_unlock(&tscm->mutex);
 125 
 126         return snd_pcm_lib_free_vmalloc_buffer(substream);
 127 }
 128 
 129 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 130 {
 131         struct snd_tscm *tscm = substream->private_data;
 132         struct snd_pcm_runtime *runtime = substream->runtime;
 133         int err;
 134 
 135         mutex_lock(&tscm->mutex);
 136 
 137         err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
 138         if (err >= 0)
 139                 amdtp_stream_pcm_prepare(&tscm->tx_stream);
 140 
 141         mutex_unlock(&tscm->mutex);
 142 
 143         return err;
 144 }
 145 
 146 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
 147 {
 148         struct snd_tscm *tscm = substream->private_data;
 149         struct snd_pcm_runtime *runtime = substream->runtime;
 150         int err;
 151 
 152         mutex_lock(&tscm->mutex);
 153 
 154         err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
 155         if (err >= 0)
 156                 amdtp_stream_pcm_prepare(&tscm->rx_stream);
 157 
 158         mutex_unlock(&tscm->mutex);
 159 
 160         return err;
 161 }
 162 
 163 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 164 {
 165         struct snd_tscm *tscm = substream->private_data;
 166 
 167         switch (cmd) {
 168         case SNDRV_PCM_TRIGGER_START:
 169                 amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
 170                 break;
 171         case SNDRV_PCM_TRIGGER_STOP:
 172                 amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
 173                 break;
 174         default:
 175                 return -EINVAL;
 176         }
 177 
 178         return 0;
 179 }
 180 
 181 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 182 {
 183         struct snd_tscm *tscm = substream->private_data;
 184 
 185         switch (cmd) {
 186         case SNDRV_PCM_TRIGGER_START:
 187                 amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
 188                 break;
 189         case SNDRV_PCM_TRIGGER_STOP:
 190                 amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
 191                 break;
 192         default:
 193                 return -EINVAL;
 194         }
 195 
 196         return 0;
 197 }
 198 
 199 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 200 {
 201         struct snd_tscm *tscm = sbstrm->private_data;
 202 
 203         return amdtp_stream_pcm_pointer(&tscm->tx_stream);
 204 }
 205 
 206 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 207 {
 208         struct snd_tscm *tscm = sbstrm->private_data;
 209 
 210         return amdtp_stream_pcm_pointer(&tscm->rx_stream);
 211 }
 212 
 213 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 214 {
 215         struct snd_tscm *tscm = substream->private_data;
 216 
 217         return amdtp_stream_pcm_ack(&tscm->tx_stream);
 218 }
 219 
 220 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 221 {
 222         struct snd_tscm *tscm = substream->private_data;
 223 
 224         return amdtp_stream_pcm_ack(&tscm->rx_stream);
 225 }
 226 
 227 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
 228 {
 229         static const struct snd_pcm_ops capture_ops = {
 230                 .open           = pcm_open,
 231                 .close          = pcm_close,
 232                 .ioctl          = snd_pcm_lib_ioctl,
 233                 .hw_params      = pcm_hw_params,
 234                 .hw_free        = pcm_hw_free,
 235                 .prepare        = pcm_capture_prepare,
 236                 .trigger        = pcm_capture_trigger,
 237                 .pointer        = pcm_capture_pointer,
 238                 .ack            = pcm_capture_ack,
 239                 .page           = snd_pcm_lib_get_vmalloc_page,
 240         };
 241         static const struct snd_pcm_ops playback_ops = {
 242                 .open           = pcm_open,
 243                 .close          = pcm_close,
 244                 .ioctl          = snd_pcm_lib_ioctl,
 245                 .hw_params      = pcm_hw_params,
 246                 .hw_free        = pcm_hw_free,
 247                 .prepare        = pcm_playback_prepare,
 248                 .trigger        = pcm_playback_trigger,
 249                 .pointer        = pcm_playback_pointer,
 250                 .ack            = pcm_playback_ack,
 251                 .page           = snd_pcm_lib_get_vmalloc_page,
 252         };
 253         struct snd_pcm *pcm;
 254         int err;
 255 
 256         err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
 257         if (err < 0)
 258                 return err;
 259 
 260         pcm->private_data = tscm;
 261         snprintf(pcm->name, sizeof(pcm->name),
 262                  "%s PCM", tscm->card->shortname);
 263         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
 264         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 265 
 266         return 0;
 267 }

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