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

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

DEFINITIONS

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

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
   4  *
   5  * Copyright (c) 2014-2015 Takashi Sakamoto
   6  */
   7 
   8 #include "digi00x.h"
   9 
  10 static int hw_rule_rate(struct snd_pcm_hw_params *params,
  11                         struct snd_pcm_hw_rule *rule)
  12 {
  13         struct snd_interval *r =
  14                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
  15         const struct snd_interval *c =
  16                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  17         struct snd_interval t = {
  18                 .min = UINT_MAX, .max = 0, .integer = 1,
  19         };
  20         unsigned int i;
  21 
  22         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
  23                 if (!snd_interval_test(c,
  24                                        snd_dg00x_stream_pcm_channels[i]))
  25                         continue;
  26 
  27                 t.min = min(t.min, snd_dg00x_stream_rates[i]);
  28                 t.max = max(t.max, snd_dg00x_stream_rates[i]);
  29         }
  30 
  31         return snd_interval_refine(r, &t);
  32 }
  33 
  34 static int hw_rule_channels(struct snd_pcm_hw_params *params,
  35                             struct snd_pcm_hw_rule *rule)
  36 {
  37         struct snd_interval *c =
  38                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  39         const struct snd_interval *r =
  40                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  41         struct snd_interval t = {
  42                 .min = UINT_MAX, .max = 0, .integer = 1,
  43         };
  44         unsigned int i;
  45 
  46         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
  47                 if (!snd_interval_test(r, snd_dg00x_stream_rates[i]))
  48                         continue;
  49 
  50                 t.min = min(t.min, snd_dg00x_stream_pcm_channels[i]);
  51                 t.max = max(t.max, snd_dg00x_stream_pcm_channels[i]);
  52         }
  53 
  54         return snd_interval_refine(c, &t);
  55 }
  56 
  57 static int pcm_init_hw_params(struct snd_dg00x *dg00x,
  58                               struct snd_pcm_substream *substream)
  59 {
  60         struct snd_pcm_runtime *runtime = substream->runtime;
  61         struct snd_pcm_hardware *hw = &runtime->hw;
  62         struct amdtp_stream *s;
  63         int err;
  64 
  65 
  66         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  67                 substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
  68                 s = &dg00x->tx_stream;
  69         } else {
  70                 substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
  71                 s = &dg00x->rx_stream;
  72         }
  73 
  74         hw->channels_min = 10;
  75         hw->channels_max = 18;
  76 
  77         hw->rates = SNDRV_PCM_RATE_44100 |
  78                     SNDRV_PCM_RATE_48000 |
  79                     SNDRV_PCM_RATE_88200 |
  80                     SNDRV_PCM_RATE_96000;
  81         snd_pcm_limit_hw_rates(runtime);
  82 
  83         err = snd_pcm_hw_rule_add(substream->runtime, 0,
  84                                   SNDRV_PCM_HW_PARAM_CHANNELS,
  85                                   hw_rule_channels, NULL,
  86                                   SNDRV_PCM_HW_PARAM_RATE, -1);
  87         if (err < 0)
  88                 return err;
  89 
  90         err = snd_pcm_hw_rule_add(substream->runtime, 0,
  91                                   SNDRV_PCM_HW_PARAM_RATE,
  92                                   hw_rule_rate, NULL,
  93                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
  94         if (err < 0)
  95                 return err;
  96 
  97         return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
  98 }
  99 
 100 static int pcm_open(struct snd_pcm_substream *substream)
 101 {
 102         struct snd_dg00x *dg00x = substream->private_data;
 103         enum snd_dg00x_clock clock;
 104         bool detect;
 105         unsigned int rate;
 106         int err;
 107 
 108         err = snd_dg00x_stream_lock_try(dg00x);
 109         if (err < 0)
 110                 goto end;
 111 
 112         err = pcm_init_hw_params(dg00x, substream);
 113         if (err < 0)
 114                 goto err_locked;
 115 
 116         /* Check current clock source. */
 117         err = snd_dg00x_stream_get_clock(dg00x, &clock);
 118         if (err < 0)
 119                 goto err_locked;
 120         if (clock != SND_DG00X_CLOCK_INTERNAL) {
 121                 err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
 122                 if (err < 0)
 123                         goto err_locked;
 124                 if (!detect) {
 125                         err = -EBUSY;
 126                         goto err_locked;
 127                 }
 128         }
 129 
 130         if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
 131             amdtp_stream_pcm_running(&dg00x->rx_stream) ||
 132             amdtp_stream_pcm_running(&dg00x->tx_stream)) {
 133                 err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
 134                 if (err < 0)
 135                         goto err_locked;
 136                 substream->runtime->hw.rate_min = rate;
 137                 substream->runtime->hw.rate_max = rate;
 138         }
 139 
 140         snd_pcm_set_sync(substream);
 141 end:
 142         return err;
 143 err_locked:
 144         snd_dg00x_stream_lock_release(dg00x);
 145         return err;
 146 }
 147 
 148 static int pcm_close(struct snd_pcm_substream *substream)
 149 {
 150         struct snd_dg00x *dg00x = substream->private_data;
 151 
 152         snd_dg00x_stream_lock_release(dg00x);
 153 
 154         return 0;
 155 }
 156 
 157 static int pcm_hw_params(struct snd_pcm_substream *substream,
 158                          struct snd_pcm_hw_params *hw_params)
 159 {
 160         struct snd_dg00x *dg00x = substream->private_data;
 161         int err;
 162 
 163         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 164                                                params_buffer_bytes(hw_params));
 165         if (err < 0)
 166                 return err;
 167 
 168         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 169                 unsigned int rate = params_rate(hw_params);
 170 
 171                 mutex_lock(&dg00x->mutex);
 172                 err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
 173                 if (err >= 0)
 174                         ++dg00x->substreams_counter;
 175                 mutex_unlock(&dg00x->mutex);
 176         }
 177 
 178         return err;
 179 }
 180 
 181 static int pcm_hw_free(struct snd_pcm_substream *substream)
 182 {
 183         struct snd_dg00x *dg00x = substream->private_data;
 184 
 185         mutex_lock(&dg00x->mutex);
 186 
 187         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 188                 --dg00x->substreams_counter;
 189 
 190         snd_dg00x_stream_stop_duplex(dg00x);
 191 
 192         mutex_unlock(&dg00x->mutex);
 193 
 194         return snd_pcm_lib_free_vmalloc_buffer(substream);
 195 }
 196 
 197 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 198 {
 199         struct snd_dg00x *dg00x = substream->private_data;
 200         int err;
 201 
 202         mutex_lock(&dg00x->mutex);
 203 
 204         err = snd_dg00x_stream_start_duplex(dg00x);
 205         if (err >= 0)
 206                 amdtp_stream_pcm_prepare(&dg00x->tx_stream);
 207 
 208         mutex_unlock(&dg00x->mutex);
 209 
 210         return err;
 211 }
 212 
 213 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
 214 {
 215         struct snd_dg00x *dg00x = substream->private_data;
 216         int err;
 217 
 218         mutex_lock(&dg00x->mutex);
 219 
 220         err = snd_dg00x_stream_start_duplex(dg00x);
 221         if (err >= 0) {
 222                 amdtp_stream_pcm_prepare(&dg00x->rx_stream);
 223                 amdtp_dot_reset(&dg00x->rx_stream);
 224         }
 225 
 226         mutex_unlock(&dg00x->mutex);
 227 
 228         return err;
 229 }
 230 
 231 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 232 {
 233         struct snd_dg00x *dg00x = substream->private_data;
 234 
 235         switch (cmd) {
 236         case SNDRV_PCM_TRIGGER_START:
 237                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
 238                 break;
 239         case SNDRV_PCM_TRIGGER_STOP:
 240                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
 241                 break;
 242         default:
 243                 return -EINVAL;
 244         }
 245 
 246         return 0;
 247 }
 248 
 249 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 250 {
 251         struct snd_dg00x *dg00x = substream->private_data;
 252 
 253         switch (cmd) {
 254         case SNDRV_PCM_TRIGGER_START:
 255                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
 256                 break;
 257         case SNDRV_PCM_TRIGGER_STOP:
 258                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
 259                 break;
 260         default:
 261                 return -EINVAL;
 262         }
 263 
 264         return 0;
 265 }
 266 
 267 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 268 {
 269         struct snd_dg00x *dg00x = sbstrm->private_data;
 270 
 271         return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
 272 }
 273 
 274 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 275 {
 276         struct snd_dg00x *dg00x = sbstrm->private_data;
 277 
 278         return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
 279 }
 280 
 281 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 282 {
 283         struct snd_dg00x *dg00x = substream->private_data;
 284 
 285         return amdtp_stream_pcm_ack(&dg00x->tx_stream);
 286 }
 287 
 288 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 289 {
 290         struct snd_dg00x *dg00x = substream->private_data;
 291 
 292         return amdtp_stream_pcm_ack(&dg00x->rx_stream);
 293 }
 294 
 295 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
 296 {
 297         static const struct snd_pcm_ops capture_ops = {
 298                 .open           = pcm_open,
 299                 .close          = pcm_close,
 300                 .ioctl          = snd_pcm_lib_ioctl,
 301                 .hw_params      = pcm_hw_params,
 302                 .hw_free        = pcm_hw_free,
 303                 .prepare        = pcm_capture_prepare,
 304                 .trigger        = pcm_capture_trigger,
 305                 .pointer        = pcm_capture_pointer,
 306                 .ack            = pcm_capture_ack,
 307                 .page           = snd_pcm_lib_get_vmalloc_page,
 308         };
 309         static const struct snd_pcm_ops playback_ops = {
 310                 .open           = pcm_open,
 311                 .close          = pcm_close,
 312                 .ioctl          = snd_pcm_lib_ioctl,
 313                 .hw_params      = pcm_hw_params,
 314                 .hw_free        = pcm_hw_free,
 315                 .prepare        = pcm_playback_prepare,
 316                 .trigger        = pcm_playback_trigger,
 317                 .pointer        = pcm_playback_pointer,
 318                 .ack            = pcm_playback_ack,
 319                 .page           = snd_pcm_lib_get_vmalloc_page,
 320         };
 321         struct snd_pcm *pcm;
 322         int err;
 323 
 324         err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
 325         if (err < 0)
 326                 return err;
 327 
 328         pcm->private_data = dg00x;
 329         snprintf(pcm->name, sizeof(pcm->name),
 330                  "%s PCM", dg00x->card->shortname);
 331         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
 332         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 333 
 334         return 0;
 335 }

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