linux/sound/firewire/dice/dice-pcm.c
<<
>>
Prefs
   1/*
   2 * dice_pcm.c - a part of driver for DICE based devices
   3 *
   4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   5 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   6 *
   7 * Licensed under the terms of the GNU General Public License, version 2.
   8 */
   9
  10#include "dice.h"
  11
  12static int limit_channels_and_rates(struct snd_dice *dice,
  13                                    struct snd_pcm_runtime *runtime,
  14                                    enum amdtp_stream_direction dir,
  15                                    unsigned int index, unsigned int size)
  16{
  17        struct snd_pcm_hardware *hw = &runtime->hw;
  18        struct amdtp_stream *stream;
  19        unsigned int rate;
  20        __be32 reg;
  21        int err;
  22
  23        /*
  24         * Retrieve current Multi Bit Linear Audio data channel and limit to
  25         * it.
  26         */
  27        if (dir == AMDTP_IN_STREAM) {
  28                stream = &dice->tx_stream[index];
  29                err = snd_dice_transaction_read_tx(dice,
  30                                size * index + TX_NUMBER_AUDIO,
  31                                &reg, sizeof(reg));
  32        } else {
  33                stream = &dice->rx_stream[index];
  34                err = snd_dice_transaction_read_rx(dice,
  35                                size * index + RX_NUMBER_AUDIO,
  36                                &reg, sizeof(reg));
  37        }
  38        if (err < 0)
  39                return err;
  40
  41        hw->channels_min = hw->channels_max = be32_to_cpu(reg);
  42
  43        /* Retrieve current sampling transfer frequency and limit to it. */
  44        err = snd_dice_transaction_get_rate(dice, &rate);
  45        if (err < 0)
  46                return err;
  47
  48        hw->rates = snd_pcm_rate_to_rate_bit(rate);
  49        snd_pcm_limit_hw_rates(runtime);
  50
  51        return 0;
  52}
  53
  54static int init_hw_info(struct snd_dice *dice,
  55                        struct snd_pcm_substream *substream)
  56{
  57        struct snd_pcm_runtime *runtime = substream->runtime;
  58        struct snd_pcm_hardware *hw = &runtime->hw;
  59        enum amdtp_stream_direction dir;
  60        struct amdtp_stream *stream;
  61        __be32 reg[2];
  62        unsigned int count, size;
  63        int err;
  64
  65        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  66                hw->formats = AM824_IN_PCM_FORMAT_BITS;
  67                dir = AMDTP_IN_STREAM;
  68                stream = &dice->tx_stream[substream->pcm->device];
  69                err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg,
  70                                                   sizeof(reg));
  71        } else {
  72                hw->formats = AM824_OUT_PCM_FORMAT_BITS;
  73                dir = AMDTP_OUT_STREAM;
  74                stream = &dice->rx_stream[substream->pcm->device];
  75                err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg,
  76                                                   sizeof(reg));
  77        }
  78
  79        if (err < 0)
  80                return err;
  81
  82        count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
  83        if (substream->pcm->device >= count)
  84                return -ENXIO;
  85
  86        size = be32_to_cpu(reg[1]) * 4;
  87        err = limit_channels_and_rates(dice, substream->runtime, dir,
  88                                       substream->pcm->device, size);
  89        if (err < 0)
  90                return err;
  91
  92        return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
  93}
  94
  95static int pcm_open(struct snd_pcm_substream *substream)
  96{
  97        struct snd_dice *dice = substream->private_data;
  98        int err;
  99
 100        err = snd_dice_stream_lock_try(dice);
 101        if (err < 0)
 102                goto end;
 103
 104        err = init_hw_info(dice, substream);
 105        if (err < 0)
 106                goto err_locked;
 107
 108        snd_pcm_set_sync(substream);
 109end:
 110        return err;
 111err_locked:
 112        snd_dice_stream_lock_release(dice);
 113        return err;
 114}
 115
 116static int pcm_close(struct snd_pcm_substream *substream)
 117{
 118        struct snd_dice *dice = substream->private_data;
 119
 120        snd_dice_stream_lock_release(dice);
 121
 122        return 0;
 123}
 124
 125static int capture_hw_params(struct snd_pcm_substream *substream,
 126                             struct snd_pcm_hw_params *hw_params)
 127{
 128        struct snd_dice *dice = substream->private_data;
 129        int err;
 130
 131        err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 132                                               params_buffer_bytes(hw_params));
 133        if (err < 0)
 134                return err;
 135
 136        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 137                mutex_lock(&dice->mutex);
 138                dice->substreams_counter++;
 139                mutex_unlock(&dice->mutex);
 140        }
 141
 142        return 0;
 143}
 144static int playback_hw_params(struct snd_pcm_substream *substream,
 145                              struct snd_pcm_hw_params *hw_params)
 146{
 147        struct snd_dice *dice = substream->private_data;
 148        int err;
 149
 150        err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 151                                               params_buffer_bytes(hw_params));
 152        if (err < 0)
 153                return err;
 154
 155        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 156                mutex_lock(&dice->mutex);
 157                dice->substreams_counter++;
 158                mutex_unlock(&dice->mutex);
 159        }
 160
 161        return 0;
 162}
 163
 164static int capture_hw_free(struct snd_pcm_substream *substream)
 165{
 166        struct snd_dice *dice = substream->private_data;
 167
 168        mutex_lock(&dice->mutex);
 169
 170        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 171                dice->substreams_counter--;
 172
 173        snd_dice_stream_stop_duplex(dice);
 174
 175        mutex_unlock(&dice->mutex);
 176
 177        return snd_pcm_lib_free_vmalloc_buffer(substream);
 178}
 179
 180static int playback_hw_free(struct snd_pcm_substream *substream)
 181{
 182        struct snd_dice *dice = substream->private_data;
 183
 184        mutex_lock(&dice->mutex);
 185
 186        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 187                dice->substreams_counter--;
 188
 189        snd_dice_stream_stop_duplex(dice);
 190
 191        mutex_unlock(&dice->mutex);
 192
 193        return snd_pcm_lib_free_vmalloc_buffer(substream);
 194}
 195
 196static int capture_prepare(struct snd_pcm_substream *substream)
 197{
 198        struct snd_dice *dice = substream->private_data;
 199        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 200        int err;
 201
 202        mutex_lock(&dice->mutex);
 203        err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
 204        mutex_unlock(&dice->mutex);
 205        if (err >= 0)
 206                amdtp_stream_pcm_prepare(stream);
 207
 208        return 0;
 209}
 210static int playback_prepare(struct snd_pcm_substream *substream)
 211{
 212        struct snd_dice *dice = substream->private_data;
 213        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 214        int err;
 215
 216        mutex_lock(&dice->mutex);
 217        err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
 218        mutex_unlock(&dice->mutex);
 219        if (err >= 0)
 220                amdtp_stream_pcm_prepare(stream);
 221
 222        return err;
 223}
 224
 225static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 226{
 227        struct snd_dice *dice = substream->private_data;
 228        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 229
 230        switch (cmd) {
 231        case SNDRV_PCM_TRIGGER_START:
 232                amdtp_stream_pcm_trigger(stream, substream);
 233                break;
 234        case SNDRV_PCM_TRIGGER_STOP:
 235                amdtp_stream_pcm_trigger(stream, NULL);
 236                break;
 237        default:
 238                return -EINVAL;
 239        }
 240
 241        return 0;
 242}
 243static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 244{
 245        struct snd_dice *dice = substream->private_data;
 246        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 247
 248        switch (cmd) {
 249        case SNDRV_PCM_TRIGGER_START:
 250                amdtp_stream_pcm_trigger(stream, substream);
 251                break;
 252        case SNDRV_PCM_TRIGGER_STOP:
 253                amdtp_stream_pcm_trigger(stream, NULL);
 254                break;
 255        default:
 256                return -EINVAL;
 257        }
 258
 259        return 0;
 260}
 261
 262static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 263{
 264        struct snd_dice *dice = substream->private_data;
 265        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 266
 267        return amdtp_stream_pcm_pointer(stream);
 268}
 269static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 270{
 271        struct snd_dice *dice = substream->private_data;
 272        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 273
 274        return amdtp_stream_pcm_pointer(stream);
 275}
 276
 277static int capture_ack(struct snd_pcm_substream *substream)
 278{
 279        struct snd_dice *dice = substream->private_data;
 280        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 281
 282        return amdtp_stream_pcm_ack(stream);
 283}
 284
 285static int playback_ack(struct snd_pcm_substream *substream)
 286{
 287        struct snd_dice *dice = substream->private_data;
 288        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 289
 290        return amdtp_stream_pcm_ack(stream);
 291}
 292
 293int snd_dice_create_pcm(struct snd_dice *dice)
 294{
 295        static const struct snd_pcm_ops capture_ops = {
 296                .open      = pcm_open,
 297                .close     = pcm_close,
 298                .ioctl     = snd_pcm_lib_ioctl,
 299                .hw_params = capture_hw_params,
 300                .hw_free   = capture_hw_free,
 301                .prepare   = capture_prepare,
 302                .trigger   = capture_trigger,
 303                .pointer   = capture_pointer,
 304                .ack       = capture_ack,
 305                .page      = snd_pcm_lib_get_vmalloc_page,
 306                .mmap      = snd_pcm_lib_mmap_vmalloc,
 307        };
 308        static const struct snd_pcm_ops playback_ops = {
 309                .open      = pcm_open,
 310                .close     = pcm_close,
 311                .ioctl     = snd_pcm_lib_ioctl,
 312                .hw_params = playback_hw_params,
 313                .hw_free   = playback_hw_free,
 314                .prepare   = playback_prepare,
 315                .trigger   = playback_trigger,
 316                .pointer   = playback_pointer,
 317                .ack       = playback_ack,
 318                .page      = snd_pcm_lib_get_vmalloc_page,
 319                .mmap      = snd_pcm_lib_mmap_vmalloc,
 320        };
 321        __be32 reg;
 322        struct snd_pcm *pcm;
 323        unsigned int i, max_capture, max_playback, capture, playback;
 324        int err;
 325
 326        /* Check whether PCM substreams are required. */
 327        if (dice->force_two_pcms) {
 328                max_capture = max_playback = 2;
 329        } else {
 330                max_capture = max_playback = 0;
 331                err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg,
 332                                                   sizeof(reg));
 333                if (err < 0)
 334                        return err;
 335                max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
 336
 337                err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg,
 338                                                   sizeof(reg));
 339                if (err < 0)
 340                        return err;
 341                max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
 342        }
 343
 344        for (i = 0; i < MAX_STREAMS; i++) {
 345                capture = playback = 0;
 346                if (i < max_capture)
 347                        capture = 1;
 348                if (i < max_playback)
 349                        playback = 1;
 350                if (capture == 0 && playback == 0)
 351                        break;
 352
 353                err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
 354                                  &pcm);
 355                if (err < 0)
 356                        return err;
 357                pcm->private_data = dice;
 358                strcpy(pcm->name, dice->card->shortname);
 359
 360                if (capture > 0)
 361                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 362                                        &capture_ops);
 363
 364                if (playback > 0)
 365                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 366                                        &playback_ops);
 367        }
 368
 369        return 0;
 370}
 371