linux/sound/firewire/digi00x/digi00x-stream.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * digi00x-stream.c - a part of driver for Digidesign Digi 002/003 family
   4 *
   5 * Copyright (c) 2014-2015 Takashi Sakamoto
   6 */
   7
   8#include "digi00x.h"
   9
  10#define CALLBACK_TIMEOUT 500
  11
  12const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
  13        [SND_DG00X_RATE_44100] = 44100,
  14        [SND_DG00X_RATE_48000] = 48000,
  15        [SND_DG00X_RATE_88200] = 88200,
  16        [SND_DG00X_RATE_96000] = 96000,
  17};
  18
  19/* Multi Bit Linear Audio data channels for each sampling transfer frequency. */
  20const unsigned int
  21snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT] = {
  22        /* Analog/ADAT/SPDIF */
  23        [SND_DG00X_RATE_44100] = (8 + 8 + 2),
  24        [SND_DG00X_RATE_48000] = (8 + 8 + 2),
  25        /* Analog/SPDIF */
  26        [SND_DG00X_RATE_88200] = (8 + 2),
  27        [SND_DG00X_RATE_96000] = (8 + 2),
  28};
  29
  30int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x, unsigned int *rate)
  31{
  32        u32 data;
  33        __be32 reg;
  34        int err;
  35
  36        err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
  37                                 DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
  38                                 &reg, sizeof(reg), 0);
  39        if (err < 0)
  40                return err;
  41
  42        data = be32_to_cpu(reg) & 0x0f;
  43        if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
  44                *rate = snd_dg00x_stream_rates[data];
  45        else
  46                err = -EIO;
  47
  48        return err;
  49}
  50
  51int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate)
  52{
  53        __be32 reg;
  54        unsigned int i;
  55
  56        for (i = 0; i < ARRAY_SIZE(snd_dg00x_stream_rates); i++) {
  57                if (rate == snd_dg00x_stream_rates[i])
  58                        break;
  59        }
  60        if (i == ARRAY_SIZE(snd_dg00x_stream_rates))
  61                return -EINVAL;
  62
  63        reg = cpu_to_be32(i);
  64        return snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
  65                                  DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
  66                                  &reg, sizeof(reg), 0);
  67}
  68
  69int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
  70                               enum snd_dg00x_clock *clock)
  71{
  72        __be32 reg;
  73        int err;
  74
  75        err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
  76                                 DG00X_ADDR_BASE + DG00X_OFFSET_CLOCK_SOURCE,
  77                                 &reg, sizeof(reg), 0);
  78        if (err < 0)
  79                return err;
  80
  81        *clock = be32_to_cpu(reg) & 0x0f;
  82        if (*clock >= SND_DG00X_CLOCK_COUNT)
  83                err = -EIO;
  84
  85        return err;
  86}
  87
  88int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect)
  89{
  90        __be32 reg;
  91        int err;
  92
  93        err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
  94                                 DG00X_ADDR_BASE + DG00X_OFFSET_DETECT_EXTERNAL,
  95                                 &reg, sizeof(reg), 0);
  96        if (err >= 0)
  97                *detect = be32_to_cpu(reg) > 0;
  98
  99        return err;
 100}
 101
 102int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
 103                                       unsigned int *rate)
 104{
 105        u32 data;
 106        __be32 reg;
 107        int err;
 108
 109        err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
 110                                 DG00X_ADDR_BASE + DG00X_OFFSET_EXTERNAL_RATE,
 111                                 &reg, sizeof(reg), 0);
 112        if (err < 0)
 113                return err;
 114
 115        data = be32_to_cpu(reg) & 0x0f;
 116        if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
 117                *rate = snd_dg00x_stream_rates[data];
 118        /* This means desync. */
 119        else
 120                err = -EBUSY;
 121
 122        return err;
 123}
 124
 125static void finish_session(struct snd_dg00x *dg00x)
 126{
 127        __be32 data;
 128
 129        amdtp_stream_stop(&dg00x->tx_stream);
 130        amdtp_stream_stop(&dg00x->rx_stream);
 131
 132        data = cpu_to_be32(0x00000003);
 133        snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
 134                           DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
 135                           &data, sizeof(data), 0);
 136
 137        // Unregister isochronous channels for both direction.
 138        data = 0;
 139        snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
 140                           DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
 141                           &data, sizeof(data), 0);
 142
 143        // Just after finishing the session, the device may lost transmitting
 144        // functionality for a short time.
 145        msleep(50);
 146}
 147
 148static int begin_session(struct snd_dg00x *dg00x)
 149{
 150        __be32 data;
 151        u32 curr;
 152        int err;
 153
 154        // Register isochronous channels for both direction.
 155        data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
 156                           dg00x->rx_resources.channel);
 157        err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
 158                                 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
 159                                 &data, sizeof(data), 0);
 160        if (err < 0)
 161                return err;
 162
 163        err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
 164                                 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
 165                                 &data, sizeof(data), 0);
 166        if (err < 0)
 167                return err;
 168        curr = be32_to_cpu(data);
 169
 170        if (curr == 0)
 171                curr = 2;
 172
 173        curr--;
 174        while (curr > 0) {
 175                data = cpu_to_be32(curr);
 176                err = snd_fw_transaction(dg00x->unit,
 177                                         TCODE_WRITE_QUADLET_REQUEST,
 178                                         DG00X_ADDR_BASE +
 179                                         DG00X_OFFSET_STREAMING_SET,
 180                                         &data, sizeof(data), 0);
 181                if (err < 0)
 182                        break;
 183
 184                msleep(20);
 185                curr--;
 186        }
 187
 188        return err;
 189}
 190
 191static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
 192                          unsigned int rate)
 193{
 194        struct fw_iso_resources *resources;
 195        int i;
 196        int err;
 197
 198        // Check sampling rate.
 199        for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
 200                if (snd_dg00x_stream_rates[i] == rate)
 201                        break;
 202        }
 203        if (i == SND_DG00X_RATE_COUNT)
 204                return -EINVAL;
 205
 206        if (stream == &dg00x->tx_stream)
 207                resources = &dg00x->tx_resources;
 208        else
 209                resources = &dg00x->rx_resources;
 210
 211        err = amdtp_dot_set_parameters(stream, rate,
 212                                       snd_dg00x_stream_pcm_channels[i]);
 213        if (err < 0)
 214                return err;
 215
 216        return fw_iso_resources_allocate(resources,
 217                                amdtp_stream_get_max_payload(stream),
 218                                fw_parent_device(dg00x->unit)->max_speed);
 219}
 220
 221int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
 222{
 223        int err;
 224
 225        /* For out-stream. */
 226        err = fw_iso_resources_init(&dg00x->rx_resources, dg00x->unit);
 227        if (err < 0)
 228                goto error;
 229        err = amdtp_dot_init(&dg00x->rx_stream, dg00x->unit, AMDTP_OUT_STREAM);
 230        if (err < 0)
 231                goto error;
 232
 233        /* For in-stream. */
 234        err = fw_iso_resources_init(&dg00x->tx_resources, dg00x->unit);
 235        if (err < 0)
 236                goto error;
 237        err = amdtp_dot_init(&dg00x->tx_stream, dg00x->unit, AMDTP_IN_STREAM);
 238        if (err < 0)
 239                goto error;
 240
 241        return 0;
 242error:
 243        snd_dg00x_stream_destroy_duplex(dg00x);
 244        return err;
 245}
 246
 247/*
 248 * This function should be called before starting streams or after stopping
 249 * streams.
 250 */
 251void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
 252{
 253        amdtp_stream_destroy(&dg00x->rx_stream);
 254        fw_iso_resources_destroy(&dg00x->rx_resources);
 255
 256        amdtp_stream_destroy(&dg00x->tx_stream);
 257        fw_iso_resources_destroy(&dg00x->tx_resources);
 258}
 259
 260int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
 261{
 262        unsigned int curr_rate;
 263        int err;
 264
 265        err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
 266        if (err < 0)
 267                return err;
 268        if (rate == 0)
 269                rate = curr_rate;
 270
 271        if (dg00x->substreams_counter == 0 || curr_rate != rate) {
 272                finish_session(dg00x);
 273
 274                fw_iso_resources_free(&dg00x->tx_resources);
 275                fw_iso_resources_free(&dg00x->rx_resources);
 276
 277                err = snd_dg00x_stream_set_local_rate(dg00x, rate);
 278                if (err < 0)
 279                        return err;
 280
 281                err = keep_resources(dg00x, &dg00x->rx_stream, rate);
 282                if (err < 0)
 283                        return err;
 284
 285                err = keep_resources(dg00x, &dg00x->tx_stream, rate);
 286                if (err < 0) {
 287                        fw_iso_resources_free(&dg00x->rx_resources);
 288                        return err;
 289                }
 290        }
 291
 292        return 0;
 293}
 294
 295int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
 296{
 297        unsigned int generation = dg00x->rx_resources.generation;
 298        int err = 0;
 299
 300        if (dg00x->substreams_counter == 0)
 301                return 0;
 302
 303        if (amdtp_streaming_error(&dg00x->tx_stream) ||
 304            amdtp_streaming_error(&dg00x->rx_stream))
 305                finish_session(dg00x);
 306
 307        if (generation != fw_parent_device(dg00x->unit)->card->generation) {
 308                err = fw_iso_resources_update(&dg00x->tx_resources);
 309                if (err < 0)
 310                        goto error;
 311
 312                err = fw_iso_resources_update(&dg00x->rx_resources);
 313                if (err < 0)
 314                        goto error;
 315        }
 316
 317        /*
 318         * No packets are transmitted without receiving packets, reagardless of
 319         * which source of clock is used.
 320         */
 321        if (!amdtp_stream_running(&dg00x->rx_stream)) {
 322                err = begin_session(dg00x);
 323                if (err < 0)
 324                        goto error;
 325
 326                err = amdtp_stream_start(&dg00x->rx_stream,
 327                                dg00x->rx_resources.channel,
 328                                fw_parent_device(dg00x->unit)->max_speed);
 329                if (err < 0)
 330                        goto error;
 331
 332                if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
 333                                              CALLBACK_TIMEOUT)) {
 334                        err = -ETIMEDOUT;
 335                        goto error;
 336                }
 337        }
 338
 339        /*
 340         * The value of SYT field in transmitted packets is always 0x0000. Thus,
 341         * duplex streams with timestamp synchronization cannot be built.
 342         */
 343        if (!amdtp_stream_running(&dg00x->tx_stream)) {
 344                err = amdtp_stream_start(&dg00x->tx_stream,
 345                                dg00x->tx_resources.channel,
 346                                fw_parent_device(dg00x->unit)->max_speed);
 347                if (err < 0)
 348                        goto error;
 349
 350                if (!amdtp_stream_wait_callback(&dg00x->tx_stream,
 351                                              CALLBACK_TIMEOUT)) {
 352                        err = -ETIMEDOUT;
 353                        goto error;
 354                }
 355        }
 356
 357        return 0;
 358error:
 359        finish_session(dg00x);
 360
 361        return err;
 362}
 363
 364void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
 365{
 366        if (dg00x->substreams_counter == 0) {
 367                finish_session(dg00x);
 368
 369                fw_iso_resources_free(&dg00x->tx_resources);
 370                fw_iso_resources_free(&dg00x->rx_resources);
 371        }
 372}
 373
 374void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
 375{
 376        fw_iso_resources_update(&dg00x->tx_resources);
 377        fw_iso_resources_update(&dg00x->rx_resources);
 378
 379        amdtp_stream_update(&dg00x->tx_stream);
 380        amdtp_stream_update(&dg00x->rx_stream);
 381}
 382
 383void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
 384{
 385        dg00x->dev_lock_changed = true;
 386        wake_up(&dg00x->hwdep_wait);
 387}
 388
 389int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
 390{
 391        int err;
 392
 393        spin_lock_irq(&dg00x->lock);
 394
 395        /* user land lock this */
 396        if (dg00x->dev_lock_count < 0) {
 397                err = -EBUSY;
 398                goto end;
 399        }
 400
 401        /* this is the first time */
 402        if (dg00x->dev_lock_count++ == 0)
 403                snd_dg00x_stream_lock_changed(dg00x);
 404        err = 0;
 405end:
 406        spin_unlock_irq(&dg00x->lock);
 407        return err;
 408}
 409
 410void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
 411{
 412        spin_lock_irq(&dg00x->lock);
 413
 414        if (WARN_ON(dg00x->dev_lock_count <= 0))
 415                goto end;
 416        if (--dg00x->dev_lock_count == 0)
 417                snd_dg00x_stream_lock_changed(dg00x);
 418end:
 419        spin_unlock_irq(&dg00x->lock);
 420}
 421