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 READY_TIMEOUT_MS        200
  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        data = cpu_to_be32(0x00000003);
 130        snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
 131                           DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
 132                           &data, sizeof(data), 0);
 133
 134        // Unregister isochronous channels for both direction.
 135        data = 0;
 136        snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
 137                           DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
 138                           &data, sizeof(data), 0);
 139
 140        // Just after finishing the session, the device may lost transmitting
 141        // functionality for a short time.
 142        msleep(50);
 143}
 144
 145static int begin_session(struct snd_dg00x *dg00x)
 146{
 147        __be32 data;
 148        u32 curr;
 149        int err;
 150
 151        // Register isochronous channels for both direction.
 152        data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
 153                           dg00x->rx_resources.channel);
 154        err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
 155                                 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
 156                                 &data, sizeof(data), 0);
 157        if (err < 0)
 158                return err;
 159
 160        err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
 161                                 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
 162                                 &data, sizeof(data), 0);
 163        if (err < 0)
 164                return err;
 165        curr = be32_to_cpu(data);
 166
 167        if (curr == 0)
 168                curr = 2;
 169
 170        curr--;
 171        while (curr > 0) {
 172                data = cpu_to_be32(curr);
 173                err = snd_fw_transaction(dg00x->unit,
 174                                         TCODE_WRITE_QUADLET_REQUEST,
 175                                         DG00X_ADDR_BASE +
 176                                         DG00X_OFFSET_STREAMING_SET,
 177                                         &data, sizeof(data), 0);
 178                if (err < 0)
 179                        break;
 180
 181                msleep(20);
 182                curr--;
 183        }
 184
 185        return err;
 186}
 187
 188static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
 189                          unsigned int rate)
 190{
 191        struct fw_iso_resources *resources;
 192        int i;
 193        int err;
 194
 195        // Check sampling rate.
 196        for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
 197                if (snd_dg00x_stream_rates[i] == rate)
 198                        break;
 199        }
 200        if (i == SND_DG00X_RATE_COUNT)
 201                return -EINVAL;
 202
 203        if (stream == &dg00x->tx_stream)
 204                resources = &dg00x->tx_resources;
 205        else
 206                resources = &dg00x->rx_resources;
 207
 208        err = amdtp_dot_set_parameters(stream, rate,
 209                                       snd_dg00x_stream_pcm_channels[i]);
 210        if (err < 0)
 211                return err;
 212
 213        return fw_iso_resources_allocate(resources,
 214                                amdtp_stream_get_max_payload(stream),
 215                                fw_parent_device(dg00x->unit)->max_speed);
 216}
 217
 218static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
 219{
 220        struct fw_iso_resources *resources;
 221        enum amdtp_stream_direction dir;
 222        int err;
 223
 224        if (s == &dg00x->tx_stream) {
 225                resources = &dg00x->tx_resources;
 226                dir = AMDTP_IN_STREAM;
 227        } else {
 228                resources = &dg00x->rx_resources;
 229                dir = AMDTP_OUT_STREAM;
 230        }
 231
 232        err = fw_iso_resources_init(resources, dg00x->unit);
 233        if (err < 0)
 234                return err;
 235
 236        err = amdtp_dot_init(s, dg00x->unit, dir);
 237        if (err < 0)
 238                fw_iso_resources_destroy(resources);
 239
 240        return err;
 241}
 242
 243static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
 244{
 245        amdtp_stream_destroy(s);
 246
 247        if (s == &dg00x->tx_stream)
 248                fw_iso_resources_destroy(&dg00x->tx_resources);
 249        else
 250                fw_iso_resources_destroy(&dg00x->rx_resources);
 251}
 252
 253int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
 254{
 255        int err;
 256
 257        err = init_stream(dg00x, &dg00x->rx_stream);
 258        if (err < 0)
 259                return err;
 260
 261        err = init_stream(dg00x, &dg00x->tx_stream);
 262        if (err < 0)
 263                destroy_stream(dg00x, &dg00x->rx_stream);
 264
 265        err = amdtp_domain_init(&dg00x->domain);
 266        if (err < 0) {
 267                destroy_stream(dg00x, &dg00x->rx_stream);
 268                destroy_stream(dg00x, &dg00x->tx_stream);
 269        }
 270
 271        return err;
 272}
 273
 274/*
 275 * This function should be called before starting streams or after stopping
 276 * streams.
 277 */
 278void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
 279{
 280        amdtp_domain_destroy(&dg00x->domain);
 281
 282        destroy_stream(dg00x, &dg00x->rx_stream);
 283        destroy_stream(dg00x, &dg00x->tx_stream);
 284}
 285
 286int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
 287                                    unsigned int frames_per_period,
 288                                    unsigned int frames_per_buffer)
 289{
 290        unsigned int curr_rate;
 291        int err;
 292
 293        err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
 294        if (err < 0)
 295                return err;
 296        if (rate == 0)
 297                rate = curr_rate;
 298
 299        if (dg00x->substreams_counter == 0 || curr_rate != rate) {
 300                amdtp_domain_stop(&dg00x->domain);
 301
 302                finish_session(dg00x);
 303
 304                fw_iso_resources_free(&dg00x->tx_resources);
 305                fw_iso_resources_free(&dg00x->rx_resources);
 306
 307                err = snd_dg00x_stream_set_local_rate(dg00x, rate);
 308                if (err < 0)
 309                        return err;
 310
 311                err = keep_resources(dg00x, &dg00x->rx_stream, rate);
 312                if (err < 0)
 313                        return err;
 314
 315                err = keep_resources(dg00x, &dg00x->tx_stream, rate);
 316                if (err < 0) {
 317                        fw_iso_resources_free(&dg00x->rx_resources);
 318                        return err;
 319                }
 320
 321                err = amdtp_domain_set_events_per_period(&dg00x->domain,
 322                                        frames_per_period, frames_per_buffer);
 323                if (err < 0) {
 324                        fw_iso_resources_free(&dg00x->rx_resources);
 325                        fw_iso_resources_free(&dg00x->tx_resources);
 326                        return err;
 327                }
 328        }
 329
 330        return 0;
 331}
 332
 333int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
 334{
 335        unsigned int generation = dg00x->rx_resources.generation;
 336        int err = 0;
 337
 338        if (dg00x->substreams_counter == 0)
 339                return 0;
 340
 341        if (amdtp_streaming_error(&dg00x->tx_stream) ||
 342            amdtp_streaming_error(&dg00x->rx_stream)) {
 343                amdtp_domain_stop(&dg00x->domain);
 344                finish_session(dg00x);
 345        }
 346
 347        if (generation != fw_parent_device(dg00x->unit)->card->generation) {
 348                err = fw_iso_resources_update(&dg00x->tx_resources);
 349                if (err < 0)
 350                        goto error;
 351
 352                err = fw_iso_resources_update(&dg00x->rx_resources);
 353                if (err < 0)
 354                        goto error;
 355        }
 356
 357        /*
 358         * No packets are transmitted without receiving packets, reagardless of
 359         * which source of clock is used.
 360         */
 361        if (!amdtp_stream_running(&dg00x->rx_stream)) {
 362                int spd = fw_parent_device(dg00x->unit)->max_speed;
 363
 364                err = begin_session(dg00x);
 365                if (err < 0)
 366                        goto error;
 367
 368                err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream,
 369                                              dg00x->rx_resources.channel, spd);
 370                if (err < 0)
 371                        goto error;
 372
 373                err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream,
 374                                              dg00x->tx_resources.channel, spd);
 375                if (err < 0)
 376                        goto error;
 377
 378                // NOTE: The device doesn't start packet transmission till receiving any packet.
 379                // It ignores presentation time expressed by the value of syt field of CIP header
 380                // in received packets. The sequence of the number of data blocks per packet is
 381                // important for media clock recovery.
 382                err = amdtp_domain_start(&dg00x->domain, 0, true, true);
 383                if (err < 0)
 384                        goto error;
 385
 386                if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) {
 387                        err = -ETIMEDOUT;
 388                        goto error;
 389                }
 390        }
 391
 392        return 0;
 393error:
 394        amdtp_domain_stop(&dg00x->domain);
 395        finish_session(dg00x);
 396
 397        return err;
 398}
 399
 400void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
 401{
 402        if (dg00x->substreams_counter == 0) {
 403                amdtp_domain_stop(&dg00x->domain);
 404                finish_session(dg00x);
 405
 406                fw_iso_resources_free(&dg00x->tx_resources);
 407                fw_iso_resources_free(&dg00x->rx_resources);
 408        }
 409}
 410
 411void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
 412{
 413        fw_iso_resources_update(&dg00x->tx_resources);
 414        fw_iso_resources_update(&dg00x->rx_resources);
 415
 416        amdtp_stream_update(&dg00x->tx_stream);
 417        amdtp_stream_update(&dg00x->rx_stream);
 418}
 419
 420void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
 421{
 422        dg00x->dev_lock_changed = true;
 423        wake_up(&dg00x->hwdep_wait);
 424}
 425
 426int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
 427{
 428        int err;
 429
 430        spin_lock_irq(&dg00x->lock);
 431
 432        /* user land lock this */
 433        if (dg00x->dev_lock_count < 0) {
 434                err = -EBUSY;
 435                goto end;
 436        }
 437
 438        /* this is the first time */
 439        if (dg00x->dev_lock_count++ == 0)
 440                snd_dg00x_stream_lock_changed(dg00x);
 441        err = 0;
 442end:
 443        spin_unlock_irq(&dg00x->lock);
 444        return err;
 445}
 446
 447void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
 448{
 449        spin_lock_irq(&dg00x->lock);
 450
 451        if (WARN_ON(dg00x->dev_lock_count <= 0))
 452                goto end;
 453        if (--dg00x->dev_lock_count == 0)
 454                snd_dg00x_stream_lock_changed(dg00x);
 455end:
 456        spin_unlock_irq(&dg00x->lock);
 457}
 458