linux/sound/firewire/dice/dice-stream.c
<<
>>
Prefs
   1/*
   2 * dice_stream.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
  12#define CALLBACK_TIMEOUT        200
  13
  14const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
  15        /* mode 0 */
  16        [0] =  32000,
  17        [1] =  44100,
  18        [2] =  48000,
  19        /* mode 1 */
  20        [3] =  88200,
  21        [4] =  96000,
  22        /* mode 2 */
  23        [5] = 176400,
  24        [6] = 192000,
  25};
  26
  27int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
  28                                  unsigned int *mode)
  29{
  30        int i;
  31
  32        for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
  33                if (!(dice->clock_caps & BIT(i)))
  34                        continue;
  35                if (snd_dice_rates[i] != rate)
  36                        continue;
  37
  38                *mode = (i - 1) / 2;
  39                return 0;
  40        }
  41        return -EINVAL;
  42}
  43
  44static void release_resources(struct snd_dice *dice,
  45                              struct fw_iso_resources *resources)
  46{
  47        unsigned int channel;
  48
  49        /* Reset channel number */
  50        channel = cpu_to_be32((u32)-1);
  51        if (resources == &dice->tx_resources)
  52                snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
  53                                              &channel, 4);
  54        else
  55                snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
  56                                              &channel, 4);
  57
  58        fw_iso_resources_free(resources);
  59}
  60
  61static int keep_resources(struct snd_dice *dice,
  62                          struct fw_iso_resources *resources,
  63                          unsigned int max_payload_bytes)
  64{
  65        unsigned int channel;
  66        int err;
  67
  68        err = fw_iso_resources_allocate(resources, max_payload_bytes,
  69                                fw_parent_device(dice->unit)->max_speed);
  70        if (err < 0)
  71                goto end;
  72
  73        /* Set channel number */
  74        channel = cpu_to_be32(resources->channel);
  75        if (resources == &dice->tx_resources)
  76                err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
  77                                                    &channel, 4);
  78        else
  79                err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
  80                                                    &channel, 4);
  81        if (err < 0)
  82                release_resources(dice, resources);
  83end:
  84        return err;
  85}
  86
  87static void stop_stream(struct snd_dice *dice, struct amdtp_stream *stream)
  88{
  89        amdtp_stream_pcm_abort(stream);
  90        amdtp_stream_stop(stream);
  91
  92        if (stream == &dice->tx_stream)
  93                release_resources(dice, &dice->tx_resources);
  94        else
  95                release_resources(dice, &dice->rx_resources);
  96}
  97
  98static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
  99                        unsigned int rate)
 100{
 101        struct fw_iso_resources *resources;
 102        unsigned int i, mode, pcm_chs, midi_ports;
 103        int err;
 104
 105        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
 106        if (err < 0)
 107                goto end;
 108        if (stream == &dice->tx_stream) {
 109                resources = &dice->tx_resources;
 110                pcm_chs = dice->tx_channels[mode];
 111                midi_ports = dice->tx_midi_ports[mode];
 112        } else {
 113                resources = &dice->rx_resources;
 114                pcm_chs = dice->rx_channels[mode];
 115                midi_ports = dice->rx_midi_ports[mode];
 116        }
 117
 118        /*
 119         * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
 120         * one data block of AMDTP packet. Thus sampling transfer frequency is
 121         * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
 122         * transferred on AMDTP packets at 96 kHz. Two successive samples of a
 123         * channel are stored consecutively in the packet. This quirk is called
 124         * as 'Dual Wire'.
 125         * For this quirk, blocking mode is required and PCM buffer size should
 126         * be aligned to SYT_INTERVAL.
 127         */
 128        if (mode > 1) {
 129                rate /= 2;
 130                pcm_chs *= 2;
 131                stream->double_pcm_frames = true;
 132        } else {
 133                stream->double_pcm_frames = false;
 134        }
 135
 136        amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports);
 137        if (mode > 1) {
 138                pcm_chs /= 2;
 139
 140                for (i = 0; i < pcm_chs; i++) {
 141                        stream->pcm_positions[i] = i * 2;
 142                        stream->pcm_positions[i + pcm_chs] = i * 2 + 1;
 143                }
 144        }
 145
 146        err = keep_resources(dice, resources,
 147                             amdtp_stream_get_max_payload(stream));
 148        if (err < 0) {
 149                dev_err(&dice->unit->device,
 150                        "fail to keep isochronous resources\n");
 151                goto end;
 152        }
 153
 154        err = amdtp_stream_start(stream, resources->channel,
 155                                 fw_parent_device(dice->unit)->max_speed);
 156        if (err < 0)
 157                release_resources(dice, resources);
 158end:
 159        return err;
 160}
 161
 162static int get_sync_mode(struct snd_dice *dice, enum cip_flags *sync_mode)
 163{
 164        u32 source;
 165        int err;
 166
 167        err = snd_dice_transaction_get_clock_source(dice, &source);
 168        if (err < 0)
 169                goto end;
 170
 171        switch (source) {
 172        /* So-called 'SYT Match' modes, sync_to_syt value of packets received */
 173        case CLOCK_SOURCE_ARX4: /* in 4th stream */
 174        case CLOCK_SOURCE_ARX3: /* in 3rd stream */
 175        case CLOCK_SOURCE_ARX2: /* in 2nd stream */
 176                err = -ENOSYS;
 177                break;
 178        case CLOCK_SOURCE_ARX1: /* in 1st stream, which this driver uses */
 179                *sync_mode = 0;
 180                break;
 181        default:
 182                *sync_mode = CIP_SYNC_TO_DEVICE;
 183                break;
 184        }
 185end:
 186        return err;
 187}
 188
 189int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
 190{
 191        struct amdtp_stream *master, *slave;
 192        unsigned int curr_rate;
 193        enum cip_flags sync_mode;
 194        int err = 0;
 195
 196        if (dice->substreams_counter == 0)
 197                goto end;
 198
 199        err = get_sync_mode(dice, &sync_mode);
 200        if (err < 0)
 201                goto end;
 202        if (sync_mode == CIP_SYNC_TO_DEVICE) {
 203                master = &dice->tx_stream;
 204                slave  = &dice->rx_stream;
 205        } else {
 206                master = &dice->rx_stream;
 207                slave  = &dice->tx_stream;
 208        }
 209
 210        /* Some packet queueing errors. */
 211        if (amdtp_streaming_error(master) || amdtp_streaming_error(slave))
 212                stop_stream(dice, master);
 213
 214        /* Stop stream if rate is different. */
 215        err = snd_dice_transaction_get_rate(dice, &curr_rate);
 216        if (err < 0) {
 217                dev_err(&dice->unit->device,
 218                        "fail to get sampling rate\n");
 219                goto end;
 220        }
 221        if (rate == 0)
 222                rate = curr_rate;
 223        if (rate != curr_rate)
 224                stop_stream(dice, master);
 225
 226        if (!amdtp_stream_running(master)) {
 227                stop_stream(dice, slave);
 228                snd_dice_transaction_clear_enable(dice);
 229
 230                amdtp_stream_set_sync(sync_mode, master, slave);
 231
 232                err = snd_dice_transaction_set_rate(dice, rate);
 233                if (err < 0) {
 234                        dev_err(&dice->unit->device,
 235                                "fail to set sampling rate\n");
 236                        goto end;
 237                }
 238
 239                /* Start both streams. */
 240                err = start_stream(dice, master, rate);
 241                if (err < 0) {
 242                        dev_err(&dice->unit->device,
 243                                "fail to start AMDTP master stream\n");
 244                        goto end;
 245                }
 246                err = start_stream(dice, slave, rate);
 247                if (err < 0) {
 248                        dev_err(&dice->unit->device,
 249                                "fail to start AMDTP slave stream\n");
 250                        stop_stream(dice, master);
 251                        goto end;
 252                }
 253                err = snd_dice_transaction_set_enable(dice);
 254                if (err < 0) {
 255                        dev_err(&dice->unit->device,
 256                                "fail to enable interface\n");
 257                        stop_stream(dice, master);
 258                        stop_stream(dice, slave);
 259                        goto end;
 260                }
 261
 262                /* Wait first callbacks */
 263                if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT) ||
 264                    !amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) {
 265                        snd_dice_transaction_clear_enable(dice);
 266                        stop_stream(dice, master);
 267                        stop_stream(dice, slave);
 268                        err = -ETIMEDOUT;
 269                }
 270        }
 271end:
 272        return err;
 273}
 274
 275void snd_dice_stream_stop_duplex(struct snd_dice *dice)
 276{
 277        if (dice->substreams_counter > 0)
 278                return;
 279
 280        snd_dice_transaction_clear_enable(dice);
 281
 282        stop_stream(dice, &dice->tx_stream);
 283        stop_stream(dice, &dice->rx_stream);
 284}
 285
 286static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 287{
 288        int err;
 289        struct fw_iso_resources *resources;
 290        enum amdtp_stream_direction dir;
 291
 292        if (stream == &dice->tx_stream) {
 293                resources = &dice->tx_resources;
 294                dir = AMDTP_IN_STREAM;
 295        } else {
 296                resources = &dice->rx_resources;
 297                dir = AMDTP_OUT_STREAM;
 298        }
 299
 300        err = fw_iso_resources_init(resources, dice->unit);
 301        if (err < 0)
 302                goto end;
 303        resources->channels_mask = 0x00000000ffffffffuLL;
 304
 305        err = amdtp_stream_init(stream, dice->unit, dir, CIP_BLOCKING);
 306        if (err < 0) {
 307                amdtp_stream_destroy(stream);
 308                fw_iso_resources_destroy(resources);
 309        }
 310end:
 311        return err;
 312}
 313
 314/*
 315 * This function should be called before starting streams or after stopping
 316 * streams.
 317 */
 318static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 319{
 320        struct fw_iso_resources *resources;
 321
 322        if (stream == &dice->tx_stream)
 323                resources = &dice->tx_resources;
 324        else
 325                resources = &dice->rx_resources;
 326
 327        amdtp_stream_destroy(stream);
 328        fw_iso_resources_destroy(resources);
 329}
 330
 331int snd_dice_stream_init_duplex(struct snd_dice *dice)
 332{
 333        int err;
 334
 335        dice->substreams_counter = 0;
 336
 337        err = init_stream(dice, &dice->tx_stream);
 338        if (err < 0)
 339                goto end;
 340
 341        err = init_stream(dice, &dice->rx_stream);
 342        if (err < 0)
 343                destroy_stream(dice, &dice->tx_stream);
 344end:
 345        return err;
 346}
 347
 348void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 349{
 350        snd_dice_transaction_clear_enable(dice);
 351
 352        destroy_stream(dice, &dice->tx_stream);
 353        destroy_stream(dice, &dice->rx_stream);
 354
 355        dice->substreams_counter = 0;
 356}
 357
 358void snd_dice_stream_update_duplex(struct snd_dice *dice)
 359{
 360        /*
 361         * On a bus reset, the DICE firmware disables streaming and then goes
 362         * off contemplating its own navel for hundreds of milliseconds before
 363         * it can react to any of our attempts to reenable streaming.  This
 364         * means that we lose synchronization anyway, so we force our streams
 365         * to stop so that the application can restart them in an orderly
 366         * manner.
 367         */
 368        dice->global_enabled = false;
 369
 370        stop_stream(dice, &dice->rx_stream);
 371        stop_stream(dice, &dice->tx_stream);
 372
 373        fw_iso_resources_update(&dice->rx_resources);
 374        fw_iso_resources_update(&dice->tx_resources);
 375}
 376
 377static void dice_lock_changed(struct snd_dice *dice)
 378{
 379        dice->dev_lock_changed = true;
 380        wake_up(&dice->hwdep_wait);
 381}
 382
 383int snd_dice_stream_lock_try(struct snd_dice *dice)
 384{
 385        int err;
 386
 387        spin_lock_irq(&dice->lock);
 388
 389        if (dice->dev_lock_count < 0) {
 390                err = -EBUSY;
 391                goto out;
 392        }
 393
 394        if (dice->dev_lock_count++ == 0)
 395                dice_lock_changed(dice);
 396        err = 0;
 397out:
 398        spin_unlock_irq(&dice->lock);
 399        return err;
 400}
 401
 402void snd_dice_stream_lock_release(struct snd_dice *dice)
 403{
 404        spin_lock_irq(&dice->lock);
 405
 406        if (WARN_ON(dice->dev_lock_count <= 0))
 407                goto out;
 408
 409        if (--dice->dev_lock_count == 0)
 410                dice_lock_changed(dice);
 411out:
 412        spin_unlock_irq(&dice->lock);
 413}
 414