linux/sound/firewire/motu/motu-stream.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * motu-stream.c - a part of driver for MOTU FireWire series
   4 *
   5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   6 */
   7
   8#include "motu.h"
   9
  10#define READY_TIMEOUT_MS        200
  11
  12#define ISOC_COMM_CONTROL_OFFSET                0x0b00
  13#define  ISOC_COMM_CONTROL_MASK                 0xffff0000
  14#define  CHANGE_RX_ISOC_COMM_STATE              0x80000000
  15#define  RX_ISOC_COMM_IS_ACTIVATED              0x40000000
  16#define  RX_ISOC_COMM_CHANNEL_MASK              0x3f000000
  17#define  RX_ISOC_COMM_CHANNEL_SHIFT             24
  18#define  CHANGE_TX_ISOC_COMM_STATE              0x00800000
  19#define  TX_ISOC_COMM_IS_ACTIVATED              0x00400000
  20#define  TX_ISOC_COMM_CHANNEL_MASK              0x003f0000
  21#define  TX_ISOC_COMM_CHANNEL_SHIFT             16
  22
  23#define PACKET_FORMAT_OFFSET                    0x0b10
  24#define  TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000080
  25#define  RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040
  26#define  TX_PACKET_TRANSMISSION_SPEED_MASK      0x0000000f
  27
  28static int keep_resources(struct snd_motu *motu, unsigned int rate,
  29                          struct amdtp_stream *stream)
  30{
  31        struct fw_iso_resources *resources;
  32        struct snd_motu_packet_format *packet_format;
  33        unsigned int midi_ports = 0;
  34        int err;
  35
  36        if (stream == &motu->rx_stream) {
  37                resources = &motu->rx_resources;
  38                packet_format = &motu->rx_packet_formats;
  39
  40                if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
  41                    (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
  42                        midi_ports = 1;
  43        } else {
  44                resources = &motu->tx_resources;
  45                packet_format = &motu->tx_packet_formats;
  46
  47                if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
  48                    (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
  49                        midi_ports = 1;
  50        }
  51
  52        err = amdtp_motu_set_parameters(stream, rate, midi_ports,
  53                                        packet_format);
  54        if (err < 0)
  55                return err;
  56
  57        return fw_iso_resources_allocate(resources,
  58                                amdtp_stream_get_max_payload(stream),
  59                                fw_parent_device(motu->unit)->max_speed);
  60}
  61
  62static int begin_session(struct snd_motu *motu)
  63{
  64        __be32 reg;
  65        u32 data;
  66        int err;
  67
  68        // Configure the unit to start isochronous communication.
  69        err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
  70                                        sizeof(reg));
  71        if (err < 0)
  72                return err;
  73        data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK;
  74
  75        data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED |
  76                (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) |
  77                CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED |
  78                (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT);
  79
  80        reg = cpu_to_be32(data);
  81        return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
  82                                          sizeof(reg));
  83}
  84
  85static void finish_session(struct snd_motu *motu)
  86{
  87        __be32 reg;
  88        u32 data;
  89        int err;
  90
  91        err = snd_motu_protocol_switch_fetching_mode(motu, false);
  92        if (err < 0)
  93                return;
  94
  95        err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
  96                                        sizeof(reg));
  97        if (err < 0)
  98                return;
  99        data = be32_to_cpu(reg);
 100
 101        data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED);
 102        data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE;
 103
 104        reg = cpu_to_be32(data);
 105        snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
 106                                   sizeof(reg));
 107}
 108
 109int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
 110{
 111        int err;
 112
 113        err = snd_motu_protocol_cache_packet_formats(motu);
 114        if (err < 0)
 115                return err;
 116
 117        if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) {
 118                motu->tx_packet_formats.midi_flag_offset = 4;
 119                motu->tx_packet_formats.midi_byte_offset = 6;
 120        } else if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q) {
 121                motu->tx_packet_formats.midi_flag_offset = 8;
 122                motu->tx_packet_formats.midi_byte_offset = 7;
 123        }
 124
 125        if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) {
 126                motu->rx_packet_formats.midi_flag_offset = 4;
 127                motu->rx_packet_formats.midi_byte_offset = 6;
 128        } else if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) {
 129                motu->rx_packet_formats.midi_flag_offset = 8;
 130                motu->rx_packet_formats.midi_byte_offset = 7;
 131        }
 132
 133        return 0;
 134}
 135
 136int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
 137                                   unsigned int frames_per_period,
 138                                   unsigned int frames_per_buffer)
 139{
 140        unsigned int curr_rate;
 141        int err;
 142
 143        err = snd_motu_protocol_get_clock_rate(motu, &curr_rate);
 144        if (err < 0)
 145                return err;
 146        if (rate == 0)
 147                rate = curr_rate;
 148
 149        if (motu->substreams_counter == 0 || curr_rate != rate) {
 150                amdtp_domain_stop(&motu->domain);
 151                finish_session(motu);
 152
 153                fw_iso_resources_free(&motu->tx_resources);
 154                fw_iso_resources_free(&motu->rx_resources);
 155
 156                kfree(motu->cache.event_offsets);
 157                motu->cache.event_offsets = NULL;
 158
 159                err = snd_motu_protocol_set_clock_rate(motu, rate);
 160                if (err < 0) {
 161                        dev_err(&motu->unit->device,
 162                                "fail to set sampling rate: %d\n", err);
 163                        return err;
 164                }
 165
 166                err = snd_motu_stream_cache_packet_formats(motu);
 167                if (err < 0)
 168                        return err;
 169
 170                err = keep_resources(motu, rate, &motu->tx_stream);
 171                if (err < 0)
 172                        return err;
 173
 174                err = keep_resources(motu, rate, &motu->rx_stream);
 175                if (err < 0) {
 176                        fw_iso_resources_free(&motu->tx_resources);
 177                        return err;
 178                }
 179
 180                err = amdtp_domain_set_events_per_period(&motu->domain,
 181                                        frames_per_period, frames_per_buffer);
 182                if (err < 0) {
 183                        fw_iso_resources_free(&motu->tx_resources);
 184                        fw_iso_resources_free(&motu->rx_resources);
 185                        return err;
 186                }
 187
 188                motu->cache.size = motu->tx_stream.syt_interval * frames_per_buffer;
 189                motu->cache.event_offsets = kcalloc(motu->cache.size, sizeof(*motu->cache.event_offsets),
 190                                                  GFP_KERNEL);
 191                if (!motu->cache.event_offsets) {
 192                        fw_iso_resources_free(&motu->tx_resources);
 193                        fw_iso_resources_free(&motu->rx_resources);
 194                        return -ENOMEM;
 195                }
 196        }
 197
 198        return 0;
 199}
 200
 201static int ensure_packet_formats(struct snd_motu *motu)
 202{
 203        __be32 reg;
 204        u32 data;
 205        int err;
 206
 207        err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, &reg,
 208                                        sizeof(reg));
 209        if (err < 0)
 210                return err;
 211        data = be32_to_cpu(reg);
 212
 213        data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS |
 214                  RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS|
 215                  TX_PACKET_TRANSMISSION_SPEED_MASK);
 216        if (motu->spec->tx_fixed_pcm_chunks[0] == motu->tx_packet_formats.pcm_chunks[0])
 217                data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
 218        if (motu->spec->rx_fixed_pcm_chunks[0] == motu->rx_packet_formats.pcm_chunks[0])
 219                data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
 220        data |= fw_parent_device(motu->unit)->max_speed;
 221
 222        reg = cpu_to_be32(data);
 223        return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, &reg,
 224                                          sizeof(reg));
 225}
 226
 227int snd_motu_stream_start_duplex(struct snd_motu *motu)
 228{
 229        unsigned int generation = motu->rx_resources.generation;
 230        int err = 0;
 231
 232        if (motu->substreams_counter == 0)
 233                return 0;
 234
 235        if (amdtp_streaming_error(&motu->rx_stream) ||
 236            amdtp_streaming_error(&motu->tx_stream)) {
 237                amdtp_domain_stop(&motu->domain);
 238                finish_session(motu);
 239        }
 240
 241        if (generation != fw_parent_device(motu->unit)->card->generation) {
 242                err = fw_iso_resources_update(&motu->rx_resources);
 243                if (err < 0)
 244                        return err;
 245
 246                err = fw_iso_resources_update(&motu->tx_resources);
 247                if (err < 0)
 248                        return err;
 249        }
 250
 251        if (!amdtp_stream_running(&motu->rx_stream)) {
 252                int spd = fw_parent_device(motu->unit)->max_speed;
 253
 254                err = ensure_packet_formats(motu);
 255                if (err < 0)
 256                        return err;
 257
 258                err = begin_session(motu);
 259                if (err < 0) {
 260                        dev_err(&motu->unit->device,
 261                                "fail to start isochronous comm: %d\n", err);
 262                        goto stop_streams;
 263                }
 264
 265                err = amdtp_domain_add_stream(&motu->domain, &motu->tx_stream,
 266                                              motu->tx_resources.channel, spd);
 267                if (err < 0)
 268                        goto stop_streams;
 269
 270                err = amdtp_domain_add_stream(&motu->domain, &motu->rx_stream,
 271                                              motu->rx_resources.channel, spd);
 272                if (err < 0)
 273                        goto stop_streams;
 274
 275                motu->cache.tail = 0;
 276                motu->cache.tx_cycle_count = UINT_MAX;
 277                motu->cache.head = 0;
 278                motu->cache.rx_cycle_count = UINT_MAX;
 279
 280                // NOTE: The device requires both of replay; the sequence of the number of data
 281                // blocks per packet, and the sequence of source packet header per data block as
 282                // presentation time.
 283                err = amdtp_domain_start(&motu->domain, 0, true, false);
 284                if (err < 0)
 285                        goto stop_streams;
 286
 287                if (!amdtp_domain_wait_ready(&motu->domain, READY_TIMEOUT_MS)) {
 288                        err = -ETIMEDOUT;
 289                        goto stop_streams;
 290                }
 291
 292                err = snd_motu_protocol_switch_fetching_mode(motu, true);
 293                if (err < 0) {
 294                        dev_err(&motu->unit->device,
 295                                "fail to enable frame fetching: %d\n", err);
 296                        goto stop_streams;
 297                }
 298        }
 299
 300        return 0;
 301
 302stop_streams:
 303        amdtp_domain_stop(&motu->domain);
 304        finish_session(motu);
 305        return err;
 306}
 307
 308void snd_motu_stream_stop_duplex(struct snd_motu *motu)
 309{
 310        if (motu->substreams_counter == 0) {
 311                amdtp_domain_stop(&motu->domain);
 312                finish_session(motu);
 313
 314                fw_iso_resources_free(&motu->tx_resources);
 315                fw_iso_resources_free(&motu->rx_resources);
 316
 317                kfree(motu->cache.event_offsets);
 318                motu->cache.event_offsets = NULL;
 319        }
 320}
 321
 322static int init_stream(struct snd_motu *motu, struct amdtp_stream *s)
 323{
 324        struct fw_iso_resources *resources;
 325        enum amdtp_stream_direction dir;
 326        int err;
 327
 328        if (s == &motu->tx_stream) {
 329                resources = &motu->tx_resources;
 330                dir = AMDTP_IN_STREAM;
 331        } else {
 332                resources = &motu->rx_resources;
 333                dir = AMDTP_OUT_STREAM;
 334        }
 335
 336        err = fw_iso_resources_init(resources, motu->unit);
 337        if (err < 0)
 338                return err;
 339
 340        err = amdtp_motu_init(s, motu->unit, dir, motu->spec, &motu->cache);
 341        if (err < 0)
 342                fw_iso_resources_destroy(resources);
 343
 344        return err;
 345}
 346
 347static void destroy_stream(struct snd_motu *motu, struct amdtp_stream *s)
 348{
 349        amdtp_stream_destroy(s);
 350
 351        if (s == &motu->tx_stream)
 352                fw_iso_resources_destroy(&motu->tx_resources);
 353        else
 354                fw_iso_resources_destroy(&motu->rx_resources);
 355}
 356
 357int snd_motu_stream_init_duplex(struct snd_motu *motu)
 358{
 359        int err;
 360
 361        err = init_stream(motu, &motu->tx_stream);
 362        if (err < 0)
 363                return err;
 364
 365        err = init_stream(motu, &motu->rx_stream);
 366        if (err < 0) {
 367                destroy_stream(motu, &motu->tx_stream);
 368                return err;
 369        }
 370
 371        err = amdtp_domain_init(&motu->domain);
 372        if (err < 0) {
 373                destroy_stream(motu, &motu->tx_stream);
 374                destroy_stream(motu, &motu->rx_stream);
 375        }
 376
 377        return err;
 378}
 379
 380// This function should be called before starting streams or after stopping
 381// streams.
 382void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
 383{
 384        amdtp_domain_destroy(&motu->domain);
 385
 386        destroy_stream(motu, &motu->rx_stream);
 387        destroy_stream(motu, &motu->tx_stream);
 388
 389        motu->substreams_counter = 0;
 390}
 391
 392static void motu_lock_changed(struct snd_motu *motu)
 393{
 394        motu->dev_lock_changed = true;
 395        wake_up(&motu->hwdep_wait);
 396}
 397
 398int snd_motu_stream_lock_try(struct snd_motu *motu)
 399{
 400        int err;
 401
 402        spin_lock_irq(&motu->lock);
 403
 404        if (motu->dev_lock_count < 0) {
 405                err = -EBUSY;
 406                goto out;
 407        }
 408
 409        if (motu->dev_lock_count++ == 0)
 410                motu_lock_changed(motu);
 411        err = 0;
 412out:
 413        spin_unlock_irq(&motu->lock);
 414        return err;
 415}
 416
 417void snd_motu_stream_lock_release(struct snd_motu *motu)
 418{
 419        spin_lock_irq(&motu->lock);
 420
 421        if (WARN_ON(motu->dev_lock_count <= 0))
 422                goto out;
 423
 424        if (--motu->dev_lock_count == 0)
 425                motu_lock_changed(motu);
 426out:
 427        spin_unlock_irq(&motu->lock);
 428}
 429