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