root/sound/firewire/tascam/tascam-stream.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_clock
  2. set_clock
  3. snd_tscm_stream_get_rate
  4. snd_tscm_stream_get_clock
  5. enable_data_channels
  6. set_stream_formats
  7. finish_session
  8. begin_session
  9. keep_resources
  10. init_stream
  11. destroy_stream
  12. snd_tscm_stream_init_duplex
  13. snd_tscm_stream_update_duplex
  14. snd_tscm_stream_destroy_duplex
  15. snd_tscm_stream_reserve_duplex
  16. snd_tscm_stream_start_duplex
  17. snd_tscm_stream_stop_duplex
  18. snd_tscm_stream_lock_changed
  19. snd_tscm_stream_lock_try
  20. snd_tscm_stream_lock_release

   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 
  16 static 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 
  44 static 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 
  97 int 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 
 125 int 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 
 141 static 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 
 177 static 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 
 193 static 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 
 222 static 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 
 281 static 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 
 301 static 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 
 334 static 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 
 344 int 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.
 368 void 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.
 378 void 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 
 386 int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
 387 {
 388         unsigned int curr_rate;
 389         int err;
 390 
 391         err = snd_tscm_stream_get_rate(tscm, &curr_rate);
 392         if (err < 0)
 393                 return err;
 394 
 395         if (tscm->substreams_counter == 0 || rate != curr_rate) {
 396                 amdtp_domain_stop(&tscm->domain);
 397 
 398                 finish_session(tscm);
 399 
 400                 fw_iso_resources_free(&tscm->tx_resources);
 401                 fw_iso_resources_free(&tscm->rx_resources);
 402 
 403                 err = set_clock(tscm, rate, INT_MAX);
 404                 if (err < 0)
 405                         return err;
 406 
 407                 err = keep_resources(tscm, rate, &tscm->tx_stream);
 408                 if (err < 0)
 409                         return err;
 410 
 411                 err = keep_resources(tscm, rate, &tscm->rx_stream);
 412                 if (err < 0) {
 413                         fw_iso_resources_free(&tscm->tx_resources);
 414                         return err;
 415                 }
 416         }
 417 
 418         return 0;
 419 }
 420 
 421 int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
 422 {
 423         unsigned int generation = tscm->rx_resources.generation;
 424         int err;
 425 
 426         if (tscm->substreams_counter == 0)
 427                 return 0;
 428 
 429         if (amdtp_streaming_error(&tscm->rx_stream) ||
 430             amdtp_streaming_error(&tscm->tx_stream)) {
 431                 amdtp_domain_stop(&tscm->domain);
 432                 finish_session(tscm);
 433         }
 434 
 435         if (generation != fw_parent_device(tscm->unit)->card->generation) {
 436                 err = fw_iso_resources_update(&tscm->tx_resources);
 437                 if (err < 0)
 438                         goto error;
 439 
 440                 err = fw_iso_resources_update(&tscm->rx_resources);
 441                 if (err < 0)
 442                         goto error;
 443         }
 444 
 445         if (!amdtp_stream_running(&tscm->rx_stream)) {
 446                 int spd = fw_parent_device(tscm->unit)->max_speed;
 447 
 448                 err = set_stream_formats(tscm, rate);
 449                 if (err < 0)
 450                         goto error;
 451 
 452                 err = begin_session(tscm);
 453                 if (err < 0)
 454                         goto error;
 455 
 456                 err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream,
 457                                               tscm->rx_resources.channel, spd);
 458                 if (err < 0)
 459                         goto error;
 460 
 461                 err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream,
 462                                               tscm->tx_resources.channel, spd);
 463                 if (err < 0)
 464                         goto error;
 465 
 466                 err = amdtp_domain_start(&tscm->domain);
 467                 if (err < 0)
 468                         return err;
 469 
 470                 if (!amdtp_stream_wait_callback(&tscm->rx_stream,
 471                                                 CALLBACK_TIMEOUT) ||
 472                     !amdtp_stream_wait_callback(&tscm->tx_stream,
 473                                                 CALLBACK_TIMEOUT)) {
 474                         err = -ETIMEDOUT;
 475                         goto error;
 476                 }
 477         }
 478 
 479         return 0;
 480 error:
 481         amdtp_domain_stop(&tscm->domain);
 482         finish_session(tscm);
 483 
 484         return err;
 485 }
 486 
 487 void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
 488 {
 489         if (tscm->substreams_counter == 0) {
 490                 amdtp_domain_stop(&tscm->domain);
 491                 finish_session(tscm);
 492 
 493                 fw_iso_resources_free(&tscm->tx_resources);
 494                 fw_iso_resources_free(&tscm->rx_resources);
 495         }
 496 }
 497 
 498 void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
 499 {
 500         tscm->dev_lock_changed = true;
 501         wake_up(&tscm->hwdep_wait);
 502 }
 503 
 504 int snd_tscm_stream_lock_try(struct snd_tscm *tscm)
 505 {
 506         int err;
 507 
 508         spin_lock_irq(&tscm->lock);
 509 
 510         /* user land lock this */
 511         if (tscm->dev_lock_count < 0) {
 512                 err = -EBUSY;
 513                 goto end;
 514         }
 515 
 516         /* this is the first time */
 517         if (tscm->dev_lock_count++ == 0)
 518                 snd_tscm_stream_lock_changed(tscm);
 519         err = 0;
 520 end:
 521         spin_unlock_irq(&tscm->lock);
 522         return err;
 523 }
 524 
 525 void snd_tscm_stream_lock_release(struct snd_tscm *tscm)
 526 {
 527         spin_lock_irq(&tscm->lock);
 528 
 529         if (WARN_ON(tscm->dev_lock_count <= 0))
 530                 goto end;
 531         if (--tscm->dev_lock_count == 0)
 532                 snd_tscm_stream_lock_changed(tscm);
 533 end:
 534         spin_unlock_irq(&tscm->lock);
 535 }

/* [<][>][^][v][top][bottom][index][help] */