linux/sound/firewire/dice/dice-pcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * dice_pcm.c - a part of driver for DICE based devices
   4 *
   5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   6 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   7 */
   8
   9#include "dice.h"
  10
  11static int dice_rate_constraint(struct snd_pcm_hw_params *params,
  12                                struct snd_pcm_hw_rule *rule)
  13{
  14        struct snd_pcm_substream *substream = rule->private;
  15        struct snd_dice *dice = substream->private_data;
  16        unsigned int index = substream->pcm->device;
  17
  18        const struct snd_interval *c =
  19                hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  20        struct snd_interval *r =
  21                hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
  22        struct snd_interval rates = {
  23                .min = UINT_MAX, .max = 0, .integer = 1
  24        };
  25        unsigned int *pcm_channels;
  26        enum snd_dice_rate_mode mode;
  27        unsigned int i, rate;
  28
  29        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  30                pcm_channels = dice->tx_pcm_chs[index];
  31        else
  32                pcm_channels = dice->rx_pcm_chs[index];
  33
  34        for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
  35                rate = snd_dice_rates[i];
  36                if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
  37                        continue;
  38
  39                if (!snd_interval_test(c, pcm_channels[mode]))
  40                        continue;
  41
  42                rates.min = min(rates.min, rate);
  43                rates.max = max(rates.max, rate);
  44        }
  45
  46        return snd_interval_refine(r, &rates);
  47}
  48
  49static int dice_channels_constraint(struct snd_pcm_hw_params *params,
  50                                    struct snd_pcm_hw_rule *rule)
  51{
  52        struct snd_pcm_substream *substream = rule->private;
  53        struct snd_dice *dice = substream->private_data;
  54        unsigned int index = substream->pcm->device;
  55
  56        const struct snd_interval *r =
  57                hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  58        struct snd_interval *c =
  59                hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  60        struct snd_interval channels = {
  61                .min = UINT_MAX, .max = 0, .integer = 1
  62        };
  63        unsigned int *pcm_channels;
  64        enum snd_dice_rate_mode mode;
  65        unsigned int i, rate;
  66
  67        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  68                pcm_channels = dice->tx_pcm_chs[index];
  69        else
  70                pcm_channels = dice->rx_pcm_chs[index];
  71
  72        for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
  73                rate = snd_dice_rates[i];
  74                if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
  75                        continue;
  76
  77                if (!snd_interval_test(r, rate))
  78                        continue;
  79
  80                channels.min = min(channels.min, pcm_channels[mode]);
  81                channels.max = max(channels.max, pcm_channels[mode]);
  82        }
  83
  84        return snd_interval_refine(c, &channels);
  85}
  86
  87static int limit_channels_and_rates(struct snd_dice *dice,
  88                                    struct snd_pcm_runtime *runtime,
  89                                    enum amdtp_stream_direction dir,
  90                                    unsigned int index)
  91{
  92        struct snd_pcm_hardware *hw = &runtime->hw;
  93        unsigned int *pcm_channels;
  94        unsigned int i;
  95
  96        if (dir == AMDTP_IN_STREAM)
  97                pcm_channels = dice->tx_pcm_chs[index];
  98        else
  99                pcm_channels = dice->rx_pcm_chs[index];
 100
 101        hw->channels_min = UINT_MAX;
 102        hw->channels_max = 0;
 103
 104        for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
 105                enum snd_dice_rate_mode mode;
 106                unsigned int rate, channels;
 107
 108                rate = snd_dice_rates[i];
 109                if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
 110                        continue;
 111                hw->rates |= snd_pcm_rate_to_rate_bit(rate);
 112
 113                channels = pcm_channels[mode];
 114                if (channels == 0)
 115                        continue;
 116                hw->channels_min = min(hw->channels_min, channels);
 117                hw->channels_max = max(hw->channels_max, channels);
 118        }
 119
 120        snd_pcm_limit_hw_rates(runtime);
 121
 122        return 0;
 123}
 124
 125static int init_hw_info(struct snd_dice *dice,
 126                        struct snd_pcm_substream *substream)
 127{
 128        struct snd_pcm_runtime *runtime = substream->runtime;
 129        struct snd_pcm_hardware *hw = &runtime->hw;
 130        unsigned int index = substream->pcm->device;
 131        enum amdtp_stream_direction dir;
 132        struct amdtp_stream *stream;
 133        int err;
 134
 135        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 136                hw->formats = AM824_IN_PCM_FORMAT_BITS;
 137                dir = AMDTP_IN_STREAM;
 138                stream = &dice->tx_stream[index];
 139        } else {
 140                hw->formats = AM824_OUT_PCM_FORMAT_BITS;
 141                dir = AMDTP_OUT_STREAM;
 142                stream = &dice->rx_stream[index];
 143        }
 144
 145        err = limit_channels_and_rates(dice, substream->runtime, dir,
 146                                       index);
 147        if (err < 0)
 148                return err;
 149
 150        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 151                                  dice_rate_constraint, substream,
 152                                  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 153        if (err < 0)
 154                return err;
 155        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 156                                  dice_channels_constraint, substream,
 157                                  SNDRV_PCM_HW_PARAM_RATE, -1);
 158        if (err < 0)
 159                return err;
 160
 161        return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
 162}
 163
 164static int pcm_open(struct snd_pcm_substream *substream)
 165{
 166        struct snd_dice *dice = substream->private_data;
 167        unsigned int source;
 168        bool internal;
 169        int err;
 170
 171        err = snd_dice_stream_lock_try(dice);
 172        if (err < 0)
 173                goto end;
 174
 175        err = init_hw_info(dice, substream);
 176        if (err < 0)
 177                goto err_locked;
 178
 179        err = snd_dice_transaction_get_clock_source(dice, &source);
 180        if (err < 0)
 181                goto err_locked;
 182        switch (source) {
 183        case CLOCK_SOURCE_AES1:
 184        case CLOCK_SOURCE_AES2:
 185        case CLOCK_SOURCE_AES3:
 186        case CLOCK_SOURCE_AES4:
 187        case CLOCK_SOURCE_AES_ANY:
 188        case CLOCK_SOURCE_ADAT:
 189        case CLOCK_SOURCE_TDIF:
 190        case CLOCK_SOURCE_WC:
 191                internal = false;
 192                break;
 193        default:
 194                internal = true;
 195                break;
 196        }
 197
 198        /*
 199         * When source of clock is not internal or any PCM streams are running,
 200         * available sampling rate is limited at current sampling rate.
 201         */
 202        if (!internal ||
 203            amdtp_stream_pcm_running(&dice->tx_stream[0]) ||
 204            amdtp_stream_pcm_running(&dice->tx_stream[1]) ||
 205            amdtp_stream_pcm_running(&dice->rx_stream[0]) ||
 206            amdtp_stream_pcm_running(&dice->rx_stream[1])) {
 207                unsigned int rate;
 208
 209                err = snd_dice_transaction_get_rate(dice, &rate);
 210                if (err < 0)
 211                        goto err_locked;
 212                substream->runtime->hw.rate_min = rate;
 213                substream->runtime->hw.rate_max = rate;
 214        }
 215
 216        snd_pcm_set_sync(substream);
 217end:
 218        return err;
 219err_locked:
 220        snd_dice_stream_lock_release(dice);
 221        return err;
 222}
 223
 224static int pcm_close(struct snd_pcm_substream *substream)
 225{
 226        struct snd_dice *dice = substream->private_data;
 227
 228        snd_dice_stream_lock_release(dice);
 229
 230        return 0;
 231}
 232
 233static int pcm_hw_params(struct snd_pcm_substream *substream,
 234                         struct snd_pcm_hw_params *hw_params)
 235{
 236        struct snd_dice *dice = substream->private_data;
 237        int err;
 238
 239        err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 240                                               params_buffer_bytes(hw_params));
 241        if (err < 0)
 242                return err;
 243
 244        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 245                unsigned int rate = params_rate(hw_params);
 246
 247                mutex_lock(&dice->mutex);
 248                err = snd_dice_stream_reserve_duplex(dice, rate);
 249                if (err >= 0)
 250                        ++dice->substreams_counter;
 251                mutex_unlock(&dice->mutex);
 252        }
 253
 254        return err;
 255}
 256
 257static int pcm_hw_free(struct snd_pcm_substream *substream)
 258{
 259        struct snd_dice *dice = substream->private_data;
 260
 261        mutex_lock(&dice->mutex);
 262
 263        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 264                --dice->substreams_counter;
 265
 266        snd_dice_stream_stop_duplex(dice);
 267
 268        mutex_unlock(&dice->mutex);
 269
 270        return snd_pcm_lib_free_vmalloc_buffer(substream);
 271}
 272
 273static int capture_prepare(struct snd_pcm_substream *substream)
 274{
 275        struct snd_dice *dice = substream->private_data;
 276        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 277        int err;
 278
 279        mutex_lock(&dice->mutex);
 280        err = snd_dice_stream_start_duplex(dice);
 281        mutex_unlock(&dice->mutex);
 282        if (err >= 0)
 283                amdtp_stream_pcm_prepare(stream);
 284
 285        return 0;
 286}
 287static int playback_prepare(struct snd_pcm_substream *substream)
 288{
 289        struct snd_dice *dice = substream->private_data;
 290        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 291        int err;
 292
 293        mutex_lock(&dice->mutex);
 294        err = snd_dice_stream_start_duplex(dice);
 295        mutex_unlock(&dice->mutex);
 296        if (err >= 0)
 297                amdtp_stream_pcm_prepare(stream);
 298
 299        return err;
 300}
 301
 302static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 303{
 304        struct snd_dice *dice = substream->private_data;
 305        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 306
 307        switch (cmd) {
 308        case SNDRV_PCM_TRIGGER_START:
 309                amdtp_stream_pcm_trigger(stream, substream);
 310                break;
 311        case SNDRV_PCM_TRIGGER_STOP:
 312                amdtp_stream_pcm_trigger(stream, NULL);
 313                break;
 314        default:
 315                return -EINVAL;
 316        }
 317
 318        return 0;
 319}
 320static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 321{
 322        struct snd_dice *dice = substream->private_data;
 323        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 324
 325        switch (cmd) {
 326        case SNDRV_PCM_TRIGGER_START:
 327                amdtp_stream_pcm_trigger(stream, substream);
 328                break;
 329        case SNDRV_PCM_TRIGGER_STOP:
 330                amdtp_stream_pcm_trigger(stream, NULL);
 331                break;
 332        default:
 333                return -EINVAL;
 334        }
 335
 336        return 0;
 337}
 338
 339static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 340{
 341        struct snd_dice *dice = substream->private_data;
 342        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 343
 344        return amdtp_stream_pcm_pointer(stream);
 345}
 346static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 347{
 348        struct snd_dice *dice = substream->private_data;
 349        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 350
 351        return amdtp_stream_pcm_pointer(stream);
 352}
 353
 354static int capture_ack(struct snd_pcm_substream *substream)
 355{
 356        struct snd_dice *dice = substream->private_data;
 357        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 358
 359        return amdtp_stream_pcm_ack(stream);
 360}
 361
 362static int playback_ack(struct snd_pcm_substream *substream)
 363{
 364        struct snd_dice *dice = substream->private_data;
 365        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 366
 367        return amdtp_stream_pcm_ack(stream);
 368}
 369
 370int snd_dice_create_pcm(struct snd_dice *dice)
 371{
 372        static const struct snd_pcm_ops capture_ops = {
 373                .open      = pcm_open,
 374                .close     = pcm_close,
 375                .ioctl     = snd_pcm_lib_ioctl,
 376                .hw_params = pcm_hw_params,
 377                .hw_free   = pcm_hw_free,
 378                .prepare   = capture_prepare,
 379                .trigger   = capture_trigger,
 380                .pointer   = capture_pointer,
 381                .ack       = capture_ack,
 382                .page      = snd_pcm_lib_get_vmalloc_page,
 383        };
 384        static const struct snd_pcm_ops playback_ops = {
 385                .open      = pcm_open,
 386                .close     = pcm_close,
 387                .ioctl     = snd_pcm_lib_ioctl,
 388                .hw_params = pcm_hw_params,
 389                .hw_free   = pcm_hw_free,
 390                .prepare   = playback_prepare,
 391                .trigger   = playback_trigger,
 392                .pointer   = playback_pointer,
 393                .ack       = playback_ack,
 394                .page      = snd_pcm_lib_get_vmalloc_page,
 395        };
 396        struct snd_pcm *pcm;
 397        unsigned int capture, playback;
 398        int i, j;
 399        int err;
 400
 401        for (i = 0; i < MAX_STREAMS; i++) {
 402                capture = playback = 0;
 403                for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) {
 404                        if (dice->tx_pcm_chs[i][j] > 0)
 405                                capture = 1;
 406                        if (dice->rx_pcm_chs[i][j] > 0)
 407                                playback = 1;
 408                }
 409
 410                err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
 411                                  &pcm);
 412                if (err < 0)
 413                        return err;
 414                pcm->private_data = dice;
 415                strcpy(pcm->name, dice->card->shortname);
 416
 417                if (capture > 0)
 418                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 419                                        &capture_ops);
 420
 421                if (playback > 0)
 422                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 423                                        &playback_ops);
 424        }
 425
 426        return 0;
 427}
 428