linux/sound/firewire/motu/motu-pcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * motu-pcm.c - a part of driver for MOTU FireWire series
   4 *
   5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   6 */
   7
   8#include <sound/pcm_params.h>
   9#include "motu.h"
  10
  11static int motu_rate_constraint(struct snd_pcm_hw_params *params,
  12                                struct snd_pcm_hw_rule *rule)
  13{
  14        struct snd_motu_packet_format *formats = rule->private;
  15
  16        const struct snd_interval *c =
  17                hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  18        struct snd_interval *r =
  19                hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
  20        struct snd_interval rates = {
  21                .min = UINT_MAX, .max = 0, .integer = 1
  22        };
  23        unsigned int i, pcm_channels, rate, mode;
  24
  25        for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
  26                rate = snd_motu_clock_rates[i];
  27                mode = i / 2;
  28
  29                pcm_channels = formats->pcm_chunks[mode];
  30                if (!snd_interval_test(c, pcm_channels))
  31                        continue;
  32
  33                rates.min = min(rates.min, rate);
  34                rates.max = max(rates.max, rate);
  35        }
  36
  37        return snd_interval_refine(r, &rates);
  38}
  39
  40static int motu_channels_constraint(struct snd_pcm_hw_params *params,
  41                                    struct snd_pcm_hw_rule *rule)
  42{
  43        struct snd_motu_packet_format *formats = rule->private;
  44
  45        const struct snd_interval *r =
  46                hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  47        struct snd_interval *c =
  48                hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  49        struct snd_interval channels = {
  50                .min = UINT_MAX, .max = 0, .integer = 1
  51        };
  52        unsigned int i, pcm_channels, rate, mode;
  53
  54        for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
  55                rate = snd_motu_clock_rates[i];
  56                mode = i / 2;
  57
  58                if (!snd_interval_test(r, rate))
  59                        continue;
  60
  61                pcm_channels = formats->pcm_chunks[mode];
  62                channels.min = min(channels.min, pcm_channels);
  63                channels.max = max(channels.max, pcm_channels);
  64        }
  65
  66        return snd_interval_refine(c, &channels);
  67}
  68
  69static void limit_channels_and_rates(struct snd_motu *motu,
  70                                     struct snd_pcm_runtime *runtime,
  71                                     struct snd_motu_packet_format *formats)
  72{
  73        struct snd_pcm_hardware *hw = &runtime->hw;
  74        unsigned int i, pcm_channels, rate, mode;
  75
  76        hw->channels_min = UINT_MAX;
  77        hw->channels_max = 0;
  78
  79        for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
  80                rate = snd_motu_clock_rates[i];
  81                mode = i / 2;
  82
  83                pcm_channels = formats->pcm_chunks[mode];
  84                if (pcm_channels == 0)
  85                        continue;
  86
  87                hw->rates |= snd_pcm_rate_to_rate_bit(rate);
  88                hw->channels_min = min(hw->channels_min, pcm_channels);
  89                hw->channels_max = max(hw->channels_max, pcm_channels);
  90        }
  91
  92        snd_pcm_limit_hw_rates(runtime);
  93}
  94
  95static int init_hw_info(struct snd_motu *motu,
  96                        struct snd_pcm_substream *substream)
  97{
  98        struct snd_pcm_runtime *runtime = substream->runtime;
  99        struct snd_pcm_hardware *hw = &runtime->hw;
 100        struct amdtp_stream *stream;
 101        struct snd_motu_packet_format *formats;
 102        int err;
 103
 104        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 105                hw->formats = SNDRV_PCM_FMTBIT_S32;
 106                stream = &motu->tx_stream;
 107                formats = &motu->tx_packet_formats;
 108        } else {
 109                hw->formats = SNDRV_PCM_FMTBIT_S32;
 110                stream = &motu->rx_stream;
 111                formats = &motu->rx_packet_formats;
 112        }
 113
 114        limit_channels_and_rates(motu, runtime, formats);
 115
 116        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 117                                  motu_rate_constraint, formats,
 118                                  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 119        if (err < 0)
 120                return err;
 121        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 122                                  motu_channels_constraint, formats,
 123                                  SNDRV_PCM_HW_PARAM_RATE, -1);
 124        if (err < 0)
 125                return err;
 126
 127        return amdtp_motu_add_pcm_hw_constraints(stream, runtime);
 128}
 129
 130static int pcm_open(struct snd_pcm_substream *substream)
 131{
 132        struct snd_motu *motu = substream->private_data;
 133        struct amdtp_domain *d = &motu->domain;
 134        enum snd_motu_clock_source src;
 135        int err;
 136
 137        err = snd_motu_stream_lock_try(motu);
 138        if (err < 0)
 139                return err;
 140
 141        mutex_lock(&motu->mutex);
 142
 143        err = snd_motu_stream_cache_packet_formats(motu);
 144        if (err < 0)
 145                goto err_locked;
 146
 147        err = init_hw_info(motu, substream);
 148        if (err < 0)
 149                goto err_locked;
 150
 151        err = snd_motu_protocol_get_clock_source(motu, &src);
 152        if (err < 0)
 153                goto err_locked;
 154
 155        // When source of clock is not internal or any stream is reserved for
 156        // transmission of PCM frames, the available sampling rate is limited
 157        // at current one.
 158        if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL &&
 159             src != SND_MOTU_CLOCK_SOURCE_SPH) ||
 160            (motu->substreams_counter > 0 && d->events_per_period > 0)) {
 161                unsigned int frames_per_period = d->events_per_period;
 162                unsigned int frames_per_buffer = d->events_per_buffer;
 163                unsigned int rate;
 164
 165                err = snd_motu_protocol_get_clock_rate(motu, &rate);
 166                if (err < 0)
 167                        goto err_locked;
 168
 169                substream->runtime->hw.rate_min = rate;
 170                substream->runtime->hw.rate_max = rate;
 171
 172                if (frames_per_period > 0) {
 173                        err = snd_pcm_hw_constraint_minmax(substream->runtime,
 174                                        SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
 175                                        frames_per_period, frames_per_period);
 176                        if (err < 0)
 177                                goto err_locked;
 178
 179                        err = snd_pcm_hw_constraint_minmax(substream->runtime,
 180                                        SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
 181                                        frames_per_buffer, frames_per_buffer);
 182                        if (err < 0)
 183                                goto err_locked;
 184                }
 185        }
 186
 187        snd_pcm_set_sync(substream);
 188
 189        mutex_unlock(&motu->mutex);
 190
 191        return 0;
 192err_locked:
 193        mutex_unlock(&motu->mutex);
 194        snd_motu_stream_lock_release(motu);
 195        return err;
 196}
 197
 198static int pcm_close(struct snd_pcm_substream *substream)
 199{
 200        struct snd_motu *motu = substream->private_data;
 201
 202        snd_motu_stream_lock_release(motu);
 203
 204        return 0;
 205}
 206
 207static int pcm_hw_params(struct snd_pcm_substream *substream,
 208                         struct snd_pcm_hw_params *hw_params)
 209{
 210        struct snd_motu *motu = substream->private_data;
 211        int err = 0;
 212
 213        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 214                unsigned int rate = params_rate(hw_params);
 215                unsigned int frames_per_period = params_period_size(hw_params);
 216                unsigned int frames_per_buffer = params_buffer_size(hw_params);
 217
 218                mutex_lock(&motu->mutex);
 219                err = snd_motu_stream_reserve_duplex(motu, rate,
 220                                        frames_per_period, frames_per_buffer);
 221                if (err >= 0)
 222                        ++motu->substreams_counter;
 223                mutex_unlock(&motu->mutex);
 224        }
 225
 226        return err;
 227}
 228
 229static int pcm_hw_free(struct snd_pcm_substream *substream)
 230{
 231        struct snd_motu *motu = substream->private_data;
 232
 233        mutex_lock(&motu->mutex);
 234
 235        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 236                --motu->substreams_counter;
 237
 238        snd_motu_stream_stop_duplex(motu);
 239
 240        mutex_unlock(&motu->mutex);
 241
 242        return 0;
 243}
 244
 245static int capture_prepare(struct snd_pcm_substream *substream)
 246{
 247        struct snd_motu *motu = substream->private_data;
 248        int err;
 249
 250        mutex_lock(&motu->mutex);
 251        err = snd_motu_stream_start_duplex(motu);
 252        mutex_unlock(&motu->mutex);
 253        if (err >= 0)
 254                amdtp_stream_pcm_prepare(&motu->tx_stream);
 255
 256        return 0;
 257}
 258static int playback_prepare(struct snd_pcm_substream *substream)
 259{
 260        struct snd_motu *motu = substream->private_data;
 261        int err;
 262
 263        mutex_lock(&motu->mutex);
 264        err = snd_motu_stream_start_duplex(motu);
 265        mutex_unlock(&motu->mutex);
 266        if (err >= 0)
 267                amdtp_stream_pcm_prepare(&motu->rx_stream);
 268
 269        return err;
 270}
 271
 272static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 273{
 274        struct snd_motu *motu = substream->private_data;
 275
 276        switch (cmd) {
 277        case SNDRV_PCM_TRIGGER_START:
 278                amdtp_stream_pcm_trigger(&motu->tx_stream, substream);
 279                break;
 280        case SNDRV_PCM_TRIGGER_STOP:
 281                amdtp_stream_pcm_trigger(&motu->tx_stream, NULL);
 282                break;
 283        default:
 284                return -EINVAL;
 285        }
 286
 287        return 0;
 288}
 289static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 290{
 291        struct snd_motu *motu = substream->private_data;
 292
 293        switch (cmd) {
 294        case SNDRV_PCM_TRIGGER_START:
 295                amdtp_stream_pcm_trigger(&motu->rx_stream, substream);
 296                break;
 297        case SNDRV_PCM_TRIGGER_STOP:
 298                amdtp_stream_pcm_trigger(&motu->rx_stream, NULL);
 299                break;
 300        default:
 301                return -EINVAL;
 302        }
 303
 304        return 0;
 305}
 306
 307static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 308{
 309        struct snd_motu *motu = substream->private_data;
 310
 311        return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->tx_stream);
 312}
 313static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 314{
 315        struct snd_motu *motu = substream->private_data;
 316
 317        return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->rx_stream);
 318}
 319
 320static int capture_ack(struct snd_pcm_substream *substream)
 321{
 322        struct snd_motu *motu = substream->private_data;
 323
 324        return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->tx_stream);
 325}
 326
 327static int playback_ack(struct snd_pcm_substream *substream)
 328{
 329        struct snd_motu *motu = substream->private_data;
 330
 331        return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->rx_stream);
 332}
 333
 334int snd_motu_create_pcm_devices(struct snd_motu *motu)
 335{
 336        static const struct snd_pcm_ops capture_ops = {
 337                .open      = pcm_open,
 338                .close     = pcm_close,
 339                .hw_params = pcm_hw_params,
 340                .hw_free   = pcm_hw_free,
 341                .prepare   = capture_prepare,
 342                .trigger   = capture_trigger,
 343                .pointer   = capture_pointer,
 344                .ack       = capture_ack,
 345        };
 346        static const struct snd_pcm_ops playback_ops = {
 347                .open      = pcm_open,
 348                .close     = pcm_close,
 349                .hw_params = pcm_hw_params,
 350                .hw_free   = pcm_hw_free,
 351                .prepare   = playback_prepare,
 352                .trigger   = playback_trigger,
 353                .pointer   = playback_pointer,
 354                .ack       = playback_ack,
 355        };
 356        struct snd_pcm *pcm;
 357        int err;
 358
 359        err = snd_pcm_new(motu->card, motu->card->driver, 0, 1, 1, &pcm);
 360        if (err < 0)
 361                return err;
 362        pcm->private_data = motu;
 363        strcpy(pcm->name, motu->card->shortname);
 364
 365        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 366        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
 367        snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
 368
 369        return 0;
 370}
 371