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 void limit_period_and_buffer(struct snd_pcm_hardware *hw)
  55{
  56        hw->periods_min = 2;                    /* SNDRV_PCM_INFO_BATCH */
  57        hw->periods_max = UINT_MAX;
  58
  59        hw->period_bytes_min = 4 * hw->channels_max;    /* byte for a frame */
  60
  61        /* Just to prevent from allocating much pages. */
  62        hw->period_bytes_max = hw->period_bytes_min * 2048;
  63        hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
  64}
  65
  66static int init_hw_info(struct snd_dice *dice,
  67                        struct snd_pcm_substream *substream)
  68{
  69        struct snd_pcm_runtime *runtime = substream->runtime;
  70        struct snd_pcm_hardware *hw = &runtime->hw;
  71        enum amdtp_stream_direction dir;
  72        struct amdtp_stream *stream;
  73        __be32 reg[2];
  74        unsigned int count, size;
  75        int err;
  76
  77        hw->info = SNDRV_PCM_INFO_MMAP |
  78                   SNDRV_PCM_INFO_MMAP_VALID |
  79                   SNDRV_PCM_INFO_BATCH |
  80                   SNDRV_PCM_INFO_INTERLEAVED |
  81                   SNDRV_PCM_INFO_JOINT_DUPLEX |
  82                   SNDRV_PCM_INFO_BLOCK_TRANSFER;
  83
  84        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  85                hw->formats = AM824_IN_PCM_FORMAT_BITS;
  86                dir = AMDTP_IN_STREAM;
  87                stream = &dice->tx_stream[substream->pcm->device];
  88                err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg,
  89                                                   sizeof(reg));
  90        } else {
  91                hw->formats = AM824_OUT_PCM_FORMAT_BITS;
  92                dir = AMDTP_OUT_STREAM;
  93                stream = &dice->rx_stream[substream->pcm->device];
  94                err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg,
  95                                                   sizeof(reg));
  96        }
  97
  98        if (err < 0)
  99                return err;
 100
 101        count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
 102        if (substream->pcm->device >= count)
 103                return -ENXIO;
 104
 105        size = be32_to_cpu(reg[1]) * 4;
 106        err = limit_channels_and_rates(dice, substream->runtime, dir,
 107                                       substream->pcm->device, size);
 108        if (err < 0)
 109                return err;
 110        limit_period_and_buffer(hw);
 111
 112        return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
 113}
 114
 115static int pcm_open(struct snd_pcm_substream *substream)
 116{
 117        struct snd_dice *dice = substream->private_data;
 118        int err;
 119
 120        err = snd_dice_stream_lock_try(dice);
 121        if (err < 0)
 122                goto end;
 123
 124        err = init_hw_info(dice, substream);
 125        if (err < 0)
 126                goto err_locked;
 127
 128        snd_pcm_set_sync(substream);
 129end:
 130        return err;
 131err_locked:
 132        snd_dice_stream_lock_release(dice);
 133        return err;
 134}
 135
 136static int pcm_close(struct snd_pcm_substream *substream)
 137{
 138        struct snd_dice *dice = substream->private_data;
 139
 140        snd_dice_stream_lock_release(dice);
 141
 142        return 0;
 143}
 144
 145static int capture_hw_params(struct snd_pcm_substream *substream,
 146                             struct snd_pcm_hw_params *hw_params)
 147{
 148        struct snd_dice *dice = substream->private_data;
 149        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 150        int err;
 151
 152        err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 153                                               params_buffer_bytes(hw_params));
 154        if (err < 0)
 155                return err;
 156
 157        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 158                mutex_lock(&dice->mutex);
 159                dice->substreams_counter++;
 160                mutex_unlock(&dice->mutex);
 161        }
 162
 163        amdtp_am824_set_pcm_format(stream, params_format(hw_params));
 164
 165        return 0;
 166}
 167static int playback_hw_params(struct snd_pcm_substream *substream,
 168                              struct snd_pcm_hw_params *hw_params)
 169{
 170        struct snd_dice *dice = substream->private_data;
 171        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 172        int err;
 173
 174        err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 175                                               params_buffer_bytes(hw_params));
 176        if (err < 0)
 177                return err;
 178
 179        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 180                mutex_lock(&dice->mutex);
 181                dice->substreams_counter++;
 182                mutex_unlock(&dice->mutex);
 183        }
 184
 185        amdtp_am824_set_pcm_format(stream, params_format(hw_params));
 186
 187        return 0;
 188}
 189
 190static int capture_hw_free(struct snd_pcm_substream *substream)
 191{
 192        struct snd_dice *dice = substream->private_data;
 193
 194        mutex_lock(&dice->mutex);
 195
 196        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 197                dice->substreams_counter--;
 198
 199        snd_dice_stream_stop_duplex(dice);
 200
 201        mutex_unlock(&dice->mutex);
 202
 203        return snd_pcm_lib_free_vmalloc_buffer(substream);
 204}
 205
 206static int playback_hw_free(struct snd_pcm_substream *substream)
 207{
 208        struct snd_dice *dice = substream->private_data;
 209
 210        mutex_lock(&dice->mutex);
 211
 212        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 213                dice->substreams_counter--;
 214
 215        snd_dice_stream_stop_duplex(dice);
 216
 217        mutex_unlock(&dice->mutex);
 218
 219        return snd_pcm_lib_free_vmalloc_buffer(substream);
 220}
 221
 222static int capture_prepare(struct snd_pcm_substream *substream)
 223{
 224        struct snd_dice *dice = substream->private_data;
 225        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 226        int err;
 227
 228        mutex_lock(&dice->mutex);
 229        err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
 230        mutex_unlock(&dice->mutex);
 231        if (err >= 0)
 232                amdtp_stream_pcm_prepare(stream);
 233
 234        return 0;
 235}
 236static int playback_prepare(struct snd_pcm_substream *substream)
 237{
 238        struct snd_dice *dice = substream->private_data;
 239        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 240        int err;
 241
 242        mutex_lock(&dice->mutex);
 243        err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
 244        mutex_unlock(&dice->mutex);
 245        if (err >= 0)
 246                amdtp_stream_pcm_prepare(stream);
 247
 248        return err;
 249}
 250
 251static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 252{
 253        struct snd_dice *dice = substream->private_data;
 254        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 255
 256        switch (cmd) {
 257        case SNDRV_PCM_TRIGGER_START:
 258                amdtp_stream_pcm_trigger(stream, substream);
 259                break;
 260        case SNDRV_PCM_TRIGGER_STOP:
 261                amdtp_stream_pcm_trigger(stream, NULL);
 262                break;
 263        default:
 264                return -EINVAL;
 265        }
 266
 267        return 0;
 268}
 269static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 270{
 271        struct snd_dice *dice = substream->private_data;
 272        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 273
 274        switch (cmd) {
 275        case SNDRV_PCM_TRIGGER_START:
 276                amdtp_stream_pcm_trigger(stream, substream);
 277                break;
 278        case SNDRV_PCM_TRIGGER_STOP:
 279                amdtp_stream_pcm_trigger(stream, NULL);
 280                break;
 281        default:
 282                return -EINVAL;
 283        }
 284
 285        return 0;
 286}
 287
 288static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 289{
 290        struct snd_dice *dice = substream->private_data;
 291        struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 292
 293        return amdtp_stream_pcm_pointer(stream);
 294}
 295static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 296{
 297        struct snd_dice *dice = substream->private_data;
 298        struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 299
 300        return amdtp_stream_pcm_pointer(stream);
 301}
 302
 303int snd_dice_create_pcm(struct snd_dice *dice)
 304{
 305        static const struct snd_pcm_ops capture_ops = {
 306                .open      = pcm_open,
 307                .close     = pcm_close,
 308                .ioctl     = snd_pcm_lib_ioctl,
 309                .hw_params = capture_hw_params,
 310                .hw_free   = capture_hw_free,
 311                .prepare   = capture_prepare,
 312                .trigger   = capture_trigger,
 313                .pointer   = capture_pointer,
 314                .page      = snd_pcm_lib_get_vmalloc_page,
 315                .mmap      = snd_pcm_lib_mmap_vmalloc,
 316        };
 317        static const struct snd_pcm_ops playback_ops = {
 318                .open      = pcm_open,
 319                .close     = pcm_close,
 320                .ioctl     = snd_pcm_lib_ioctl,
 321                .hw_params = playback_hw_params,
 322                .hw_free   = playback_hw_free,
 323                .prepare   = playback_prepare,
 324                .trigger   = playback_trigger,
 325                .pointer   = playback_pointer,
 326                .page      = snd_pcm_lib_get_vmalloc_page,
 327                .mmap      = snd_pcm_lib_mmap_vmalloc,
 328        };
 329        __be32 reg;
 330        struct snd_pcm *pcm;
 331        unsigned int i, max_capture, max_playback, capture, playback;
 332        int err;
 333
 334        /* Check whether PCM substreams are required. */
 335        if (dice->force_two_pcms) {
 336                max_capture = max_playback = 2;
 337        } else {
 338                max_capture = max_playback = 0;
 339                err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg,
 340                                                   sizeof(reg));
 341                if (err < 0)
 342                        return err;
 343                max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
 344
 345                err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg,
 346                                                   sizeof(reg));
 347                if (err < 0)
 348                        return err;
 349                max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
 350        }
 351
 352        for (i = 0; i < MAX_STREAMS; i++) {
 353                capture = playback = 0;
 354                if (i < max_capture)
 355                        capture = 1;
 356                if (i < max_playback)
 357                        playback = 1;
 358                if (capture == 0 && playback == 0)
 359                        break;
 360
 361                err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
 362                                  &pcm);
 363                if (err < 0)
 364                        return err;
 365                pcm->private_data = dice;
 366                strcpy(pcm->name, dice->card->shortname);
 367
 368                if (capture > 0)
 369                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 370                                        &capture_ops);
 371
 372                if (playback > 0)
 373                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 374                                        &playback_ops);
 375        }
 376
 377        return 0;
 378}
 379