linux/sound/firewire/tascam/tascam-stream.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * tascam-stream.c - a part of driver for TASCAM FireWire series
   4 *
   5 * Copyright (c) 2015 Takashi Sakamoto
   6 */
   7
   8#include <linux/delay.h>
   9#include "tascam.h"
  10
  11#define CALLBACK_TIMEOUT 500
  12
  13static int get_clock(struct snd_tscm *tscm, u32 *data)
  14{
  15        __be32 reg;
  16        int err;
  17
  18        err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,
  19                                 TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,
  20                                 &reg, sizeof(reg), 0);
  21        if (err >= 0)
  22                *data = be32_to_cpu(reg);
  23
  24        return err;
  25}
  26
  27static int set_clock(struct snd_tscm *tscm, unsigned int rate,
  28                     enum snd_tscm_clock clock)
  29{
  30        u32 data;
  31        __be32 reg;
  32        int err;
  33
  34        err = get_clock(tscm, &data);
  35        if (err < 0)
  36                return err;
  37        data &= 0x0000ffff;
  38
  39        if (rate > 0) {
  40                data &= 0x000000ff;
  41                /* Base rate. */
  42                if ((rate % 44100) == 0) {
  43                        data |= 0x00000100;
  44                        /* Multiplier. */
  45                        if (rate / 44100 == 2)
  46                                data |= 0x00008000;
  47                } else if ((rate % 48000) == 0) {
  48                        data |= 0x00000200;
  49                        /* Multiplier. */
  50                        if (rate / 48000 == 2)
  51                                data |= 0x00008000;
  52                } else {
  53                        return -EAGAIN;
  54                }
  55        }
  56
  57        if (clock != INT_MAX) {
  58                data &= 0x0000ff00;
  59                data |= clock + 1;
  60        }
  61
  62        reg = cpu_to_be32(data);
  63
  64        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  65                                 TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,
  66                                 &reg, sizeof(reg), 0);
  67        if (err < 0)
  68                return err;
  69
  70        if (data & 0x00008000)
  71                reg = cpu_to_be32(0x0000001a);
  72        else
  73                reg = cpu_to_be32(0x0000000d);
  74
  75        return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  76                                  TSCM_ADDR_BASE + TSCM_OFFSET_MULTIPLEX_MODE,
  77                                  &reg, sizeof(reg), 0);
  78}
  79
  80int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate)
  81{
  82        u32 data = 0x0;
  83        unsigned int trials = 0;
  84        int err;
  85
  86        while (data == 0x0 || trials++ < 5) {
  87                err = get_clock(tscm, &data);
  88                if (err < 0)
  89                        return err;
  90
  91                data = (data & 0xff000000) >> 24;
  92        }
  93
  94        /* Check base rate. */
  95        if ((data & 0x0f) == 0x01)
  96                *rate = 44100;
  97        else if ((data & 0x0f) == 0x02)
  98                *rate = 48000;
  99        else
 100                return -EAGAIN;
 101
 102        /* Check multiplier. */
 103        if ((data & 0xf0) == 0x80)
 104                *rate *= 2;
 105        else if ((data & 0xf0) != 0x00)
 106                return -EAGAIN;
 107
 108        return err;
 109}
 110
 111int snd_tscm_stream_get_clock(struct snd_tscm *tscm, enum snd_tscm_clock *clock)
 112{
 113        u32 data;
 114        int err;
 115
 116        err = get_clock(tscm, &data);
 117        if (err < 0)
 118                return err;
 119
 120        *clock = ((data & 0x00ff0000) >> 16) - 1;
 121        if (*clock < 0 || *clock > SND_TSCM_CLOCK_ADAT)
 122                return -EIO;
 123
 124        return 0;
 125}
 126
 127static int enable_data_channels(struct snd_tscm *tscm)
 128{
 129        __be32 reg;
 130        u32 data;
 131        unsigned int i;
 132        int err;
 133
 134        data = 0;
 135        for (i = 0; i < tscm->spec->pcm_capture_analog_channels; ++i)
 136                data |= BIT(i);
 137        if (tscm->spec->has_adat)
 138                data |= 0x0000ff00;
 139        if (tscm->spec->has_spdif)
 140                data |= 0x00030000;
 141
 142        reg = cpu_to_be32(data);
 143        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 144                                 TSCM_ADDR_BASE + TSCM_OFFSET_TX_PCM_CHANNELS,
 145                                 &reg, sizeof(reg), 0);
 146        if (err < 0)
 147                return err;
 148
 149        data = 0;
 150        for (i = 0; i < tscm->spec->pcm_playback_analog_channels; ++i)
 151                data |= BIT(i);
 152        if (tscm->spec->has_adat)
 153                data |= 0x0000ff00;
 154        if (tscm->spec->has_spdif)
 155                data |= 0x00030000;
 156
 157        reg = cpu_to_be32(data);
 158        return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 159                                  TSCM_ADDR_BASE + TSCM_OFFSET_RX_PCM_CHANNELS,
 160                                  &reg, sizeof(reg), 0);
 161}
 162
 163static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
 164{
 165        __be32 reg;
 166        int err;
 167
 168        // Set an option for unknown purpose.
 169        reg = cpu_to_be32(0x00200000);
 170        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 171                                 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
 172                                 &reg, sizeof(reg), 0);
 173        if (err < 0)
 174                return err;
 175
 176        return enable_data_channels(tscm);
 177}
 178
 179static void finish_session(struct snd_tscm *tscm)
 180{
 181        __be32 reg;
 182
 183        amdtp_stream_stop(&tscm->rx_stream);
 184        amdtp_stream_stop(&tscm->tx_stream);
 185
 186        reg = 0;
 187        snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 188                           TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
 189                           &reg, sizeof(reg), 0);
 190
 191        reg = 0;
 192        snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 193                           TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
 194                           &reg, sizeof(reg), 0);
 195
 196        // Unregister channels.
 197        reg = cpu_to_be32(0x00000000);
 198        snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 199                           TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
 200                           &reg, sizeof(reg), 0);
 201        reg = cpu_to_be32(0x00000000);
 202        snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 203                           TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
 204                           &reg, sizeof(reg), 0);
 205        reg = cpu_to_be32(0x00000000);
 206        snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 207                           TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
 208                           &reg, sizeof(reg), 0);
 209}
 210
 211static int begin_session(struct snd_tscm *tscm)
 212{
 213        __be32 reg;
 214        int err;
 215
 216        // Register the isochronous channel for transmitting stream.
 217        reg = cpu_to_be32(tscm->tx_resources.channel);
 218        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 219                                 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
 220                                 &reg, sizeof(reg), 0);
 221        if (err < 0)
 222                return err;
 223
 224        // Unknown.
 225        reg = cpu_to_be32(0x00000002);
 226        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 227                                 TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
 228                                 &reg, sizeof(reg), 0);
 229        if (err < 0)
 230                return err;
 231
 232        // Register the isochronous channel for receiving stream.
 233        reg = cpu_to_be32(tscm->rx_resources.channel);
 234        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 235                                 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
 236                                 &reg, sizeof(reg), 0);
 237        if (err < 0)
 238                return err;
 239
 240        reg = cpu_to_be32(0x00000001);
 241        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 242                                 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
 243                                 &reg, sizeof(reg), 0);
 244        if (err < 0)
 245                return err;
 246
 247        reg = cpu_to_be32(0x00000001);
 248        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 249                                 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
 250                                 &reg, sizeof(reg), 0);
 251        if (err < 0)
 252                return err;
 253
 254        // Set an option for unknown purpose.
 255        reg = cpu_to_be32(0x00002000);
 256        err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
 257                                 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
 258                                 &reg, sizeof(reg), 0);
 259        if (err < 0)
 260                return err;
 261
 262        // Start multiplexing PCM samples on packets.
 263        reg = cpu_to_be32(0x00000001);
 264        return snd_fw_transaction(tscm->unit,
 265                                  TCODE_WRITE_QUADLET_REQUEST,
 266                                  TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_ON,
 267                                  &reg, sizeof(reg), 0);
 268}
 269
 270static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
 271                          struct amdtp_stream *stream)
 272{
 273        struct fw_iso_resources *resources;
 274        int err;
 275
 276        if (stream == &tscm->tx_stream)
 277                resources = &tscm->tx_resources;
 278        else
 279                resources = &tscm->rx_resources;
 280
 281        err = amdtp_tscm_set_parameters(stream, rate);
 282        if (err < 0)
 283                return err;
 284
 285        return fw_iso_resources_allocate(resources,
 286                                amdtp_stream_get_max_payload(stream),
 287                                fw_parent_device(tscm->unit)->max_speed);
 288}
 289
 290int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
 291{
 292        unsigned int pcm_channels;
 293        int err;
 294
 295        /* For out-stream. */
 296        err = fw_iso_resources_init(&tscm->rx_resources, tscm->unit);
 297        if (err < 0)
 298                return err;
 299        pcm_channels = tscm->spec->pcm_playback_analog_channels;
 300        if (tscm->spec->has_adat)
 301                pcm_channels += 8;
 302        if (tscm->spec->has_spdif)
 303                pcm_channels += 2;
 304        err = amdtp_tscm_init(&tscm->rx_stream, tscm->unit, AMDTP_OUT_STREAM,
 305                              pcm_channels);
 306        if (err < 0)
 307                return err;
 308
 309        /* For in-stream. */
 310        err = fw_iso_resources_init(&tscm->tx_resources, tscm->unit);
 311        if (err < 0)
 312                return err;
 313        pcm_channels = tscm->spec->pcm_capture_analog_channels;
 314        if (tscm->spec->has_adat)
 315                pcm_channels += 8;
 316        if (tscm->spec->has_spdif)
 317                pcm_channels += 2;
 318        err = amdtp_tscm_init(&tscm->tx_stream, tscm->unit, AMDTP_IN_STREAM,
 319                              pcm_channels);
 320        if (err < 0)
 321                amdtp_stream_destroy(&tscm->rx_stream);
 322
 323        return err;
 324}
 325
 326// At bus reset, streaming is stopped and some registers are clear.
 327void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
 328{
 329        amdtp_stream_pcm_abort(&tscm->tx_stream);
 330        amdtp_stream_stop(&tscm->tx_stream);
 331
 332        amdtp_stream_pcm_abort(&tscm->rx_stream);
 333        amdtp_stream_stop(&tscm->rx_stream);
 334}
 335
 336/*
 337 * This function should be called before starting streams or after stopping
 338 * streams.
 339 */
 340void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
 341{
 342        amdtp_stream_destroy(&tscm->rx_stream);
 343        amdtp_stream_destroy(&tscm->tx_stream);
 344
 345        fw_iso_resources_destroy(&tscm->rx_resources);
 346        fw_iso_resources_destroy(&tscm->tx_resources);
 347}
 348
 349int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
 350{
 351        unsigned int curr_rate;
 352        int err;
 353
 354        err = snd_tscm_stream_get_rate(tscm, &curr_rate);
 355        if (err < 0)
 356                return err;
 357
 358        if (tscm->substreams_counter == 0 || rate != curr_rate) {
 359                finish_session(tscm);
 360
 361                fw_iso_resources_free(&tscm->tx_resources);
 362                fw_iso_resources_free(&tscm->rx_resources);
 363
 364                err = set_clock(tscm, rate, INT_MAX);
 365                if (err < 0)
 366                        return err;
 367
 368                err = keep_resources(tscm, rate, &tscm->tx_stream);
 369                if (err < 0)
 370                        return err;
 371
 372                err = keep_resources(tscm, rate, &tscm->rx_stream);
 373                if (err < 0) {
 374                        fw_iso_resources_free(&tscm->tx_resources);
 375                        return err;
 376                }
 377        }
 378
 379        return 0;
 380}
 381
 382int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
 383{
 384        unsigned int generation = tscm->rx_resources.generation;
 385        int err;
 386
 387        if (tscm->substreams_counter == 0)
 388                return 0;
 389
 390        if (amdtp_streaming_error(&tscm->rx_stream) ||
 391            amdtp_streaming_error(&tscm->tx_stream))
 392                finish_session(tscm);
 393
 394        if (generation != fw_parent_device(tscm->unit)->card->generation) {
 395                err = fw_iso_resources_update(&tscm->tx_resources);
 396                if (err < 0)
 397                        goto error;
 398
 399                err = fw_iso_resources_update(&tscm->rx_resources);
 400                if (err < 0)
 401                        goto error;
 402        }
 403
 404        if (!amdtp_stream_running(&tscm->rx_stream)) {
 405                err = set_stream_formats(tscm, rate);
 406                if (err < 0)
 407                        goto error;
 408
 409                err = begin_session(tscm);
 410                if (err < 0)
 411                        goto error;
 412
 413                err = amdtp_stream_start(&tscm->rx_stream,
 414                                tscm->rx_resources.channel,
 415                                fw_parent_device(tscm->unit)->max_speed);
 416                if (err < 0)
 417                        goto error;
 418
 419                if (!amdtp_stream_wait_callback(&tscm->rx_stream,
 420                                                CALLBACK_TIMEOUT)) {
 421                        err = -ETIMEDOUT;
 422                        goto error;
 423                }
 424        }
 425
 426        if (!amdtp_stream_running(&tscm->tx_stream)) {
 427                err = amdtp_stream_start(&tscm->tx_stream,
 428                                tscm->tx_resources.channel,
 429                                fw_parent_device(tscm->unit)->max_speed);
 430                if (err < 0)
 431                        goto error;
 432
 433                if (!amdtp_stream_wait_callback(&tscm->tx_stream,
 434                                                CALLBACK_TIMEOUT)) {
 435                        err = -ETIMEDOUT;
 436                        goto error;
 437                }
 438        }
 439
 440        return 0;
 441error:
 442        finish_session(tscm);
 443
 444        return err;
 445}
 446
 447void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
 448{
 449        if (tscm->substreams_counter == 0) {
 450                finish_session(tscm);
 451
 452                fw_iso_resources_free(&tscm->tx_resources);
 453                fw_iso_resources_free(&tscm->rx_resources);
 454        }
 455}
 456
 457void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
 458{
 459        tscm->dev_lock_changed = true;
 460        wake_up(&tscm->hwdep_wait);
 461}
 462
 463int snd_tscm_stream_lock_try(struct snd_tscm *tscm)
 464{
 465        int err;
 466
 467        spin_lock_irq(&tscm->lock);
 468
 469        /* user land lock this */
 470        if (tscm->dev_lock_count < 0) {
 471                err = -EBUSY;
 472                goto end;
 473        }
 474
 475        /* this is the first time */
 476        if (tscm->dev_lock_count++ == 0)
 477                snd_tscm_stream_lock_changed(tscm);
 478        err = 0;
 479end:
 480        spin_unlock_irq(&tscm->lock);
 481        return err;
 482}
 483
 484void snd_tscm_stream_lock_release(struct snd_tscm *tscm)
 485{
 486        spin_lock_irq(&tscm->lock);
 487
 488        if (WARN_ON(tscm->dev_lock_count <= 0))
 489                goto end;
 490        if (--tscm->dev_lock_count == 0)
 491                snd_tscm_stream_lock_changed(tscm);
 492end:
 493        spin_unlock_irq(&tscm->lock);
 494}
 495