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