linux/sound/firewire/dice/dice-stream.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * dice_stream.c - a part of driver for DICE based devices
   4 *
   5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   6 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   7 */
   8
   9#include "dice.h"
  10
  11#define CALLBACK_TIMEOUT        200
  12#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC)
  13
  14struct reg_params {
  15        unsigned int count;
  16        unsigned int size;
  17};
  18
  19const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
  20        /* mode 0 */
  21        [0] =  32000,
  22        [1] =  44100,
  23        [2] =  48000,
  24        /* mode 1 */
  25        [3] =  88200,
  26        [4] =  96000,
  27        /* mode 2 */
  28        [5] = 176400,
  29        [6] = 192000,
  30};
  31
  32int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
  33                                  enum snd_dice_rate_mode *mode)
  34{
  35        /* Corresponding to each entry in snd_dice_rates. */
  36        static const enum snd_dice_rate_mode modes[] = {
  37                [0] = SND_DICE_RATE_MODE_LOW,
  38                [1] = SND_DICE_RATE_MODE_LOW,
  39                [2] = SND_DICE_RATE_MODE_LOW,
  40                [3] = SND_DICE_RATE_MODE_MIDDLE,
  41                [4] = SND_DICE_RATE_MODE_MIDDLE,
  42                [5] = SND_DICE_RATE_MODE_HIGH,
  43                [6] = SND_DICE_RATE_MODE_HIGH,
  44        };
  45        int i;
  46
  47        for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
  48                if (!(dice->clock_caps & BIT(i)))
  49                        continue;
  50                if (snd_dice_rates[i] != rate)
  51                        continue;
  52
  53                *mode = modes[i];
  54                return 0;
  55        }
  56
  57        return -EINVAL;
  58}
  59
  60/*
  61 * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE
  62 * to GLOBAL_STATUS. Especially, just after powering on, these are different.
  63 */
  64static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate)
  65{
  66        __be32 reg, nominal;
  67        u32 data;
  68        int i;
  69        int err;
  70
  71        err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
  72                                               &reg, sizeof(reg));
  73        if (err < 0)
  74                return err;
  75
  76        data = be32_to_cpu(reg);
  77
  78        data &= ~CLOCK_RATE_MASK;
  79        for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
  80                if (snd_dice_rates[i] == rate)
  81                        break;
  82        }
  83        if (i == ARRAY_SIZE(snd_dice_rates))
  84                return -EINVAL;
  85        data |= i << CLOCK_RATE_SHIFT;
  86
  87        if (completion_done(&dice->clock_accepted))
  88                reinit_completion(&dice->clock_accepted);
  89
  90        reg = cpu_to_be32(data);
  91        err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
  92                                                &reg, sizeof(reg));
  93        if (err < 0)
  94                return err;
  95
  96        if (wait_for_completion_timeout(&dice->clock_accepted,
  97                        msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
  98                /*
  99                 * Old versions of Dice firmware transfer no notification when
 100                 * the same clock status as current one is set. In this case,
 101                 * just check current clock status.
 102                 */
 103                err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS,
 104                                                &nominal, sizeof(nominal));
 105                if (err < 0)
 106                        return err;
 107                if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED))
 108                        return -ETIMEDOUT;
 109        }
 110
 111        return 0;
 112}
 113
 114static int get_register_params(struct snd_dice *dice,
 115                               struct reg_params *tx_params,
 116                               struct reg_params *rx_params)
 117{
 118        __be32 reg[2];
 119        int err;
 120
 121        err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
 122        if (err < 0)
 123                return err;
 124        tx_params->count =
 125                        min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
 126        tx_params->size = be32_to_cpu(reg[1]) * 4;
 127
 128        err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
 129        if (err < 0)
 130                return err;
 131        rx_params->count =
 132                        min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
 133        rx_params->size = be32_to_cpu(reg[1]) * 4;
 134
 135        return 0;
 136}
 137
 138static void release_resources(struct snd_dice *dice)
 139{
 140        int i;
 141
 142        for (i = 0; i < MAX_STREAMS; ++i) {
 143                fw_iso_resources_free(&dice->tx_resources[i]);
 144                fw_iso_resources_free(&dice->rx_resources[i]);
 145        }
 146}
 147
 148static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
 149                         struct reg_params *params)
 150{
 151        __be32 reg;
 152        unsigned int i;
 153
 154        for (i = 0; i < params->count; i++) {
 155                reg = cpu_to_be32((u32)-1);
 156                if (dir == AMDTP_IN_STREAM) {
 157                        snd_dice_transaction_write_tx(dice,
 158                                        params->size * i + TX_ISOCHRONOUS,
 159                                        &reg, sizeof(reg));
 160                } else {
 161                        snd_dice_transaction_write_rx(dice,
 162                                        params->size * i + RX_ISOCHRONOUS,
 163                                        &reg, sizeof(reg));
 164                }
 165        }
 166}
 167
 168static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
 169                          struct fw_iso_resources *resources, unsigned int rate,
 170                          unsigned int pcm_chs, unsigned int midi_ports)
 171{
 172        bool double_pcm_frames;
 173        unsigned int i;
 174        int err;
 175
 176        // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
 177        // one data block of AMDTP packet. Thus sampling transfer frequency is
 178        // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
 179        // transferred on AMDTP packets at 96 kHz. Two successive samples of a
 180        // channel are stored consecutively in the packet. This quirk is called
 181        // as 'Dual Wire'.
 182        // For this quirk, blocking mode is required and PCM buffer size should
 183        // be aligned to SYT_INTERVAL.
 184        double_pcm_frames = rate > 96000;
 185        if (double_pcm_frames) {
 186                rate /= 2;
 187                pcm_chs *= 2;
 188        }
 189
 190        err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
 191                                         double_pcm_frames);
 192        if (err < 0)
 193                return err;
 194
 195        if (double_pcm_frames) {
 196                pcm_chs /= 2;
 197
 198                for (i = 0; i < pcm_chs; i++) {
 199                        amdtp_am824_set_pcm_position(stream, i, i * 2);
 200                        amdtp_am824_set_pcm_position(stream, i + pcm_chs,
 201                                                     i * 2 + 1);
 202                }
 203        }
 204
 205        return fw_iso_resources_allocate(resources,
 206                                amdtp_stream_get_max_payload(stream),
 207                                fw_parent_device(dice->unit)->max_speed);
 208}
 209
 210static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
 211                               enum amdtp_stream_direction dir,
 212                               struct reg_params *params)
 213{
 214        enum snd_dice_rate_mode mode;
 215        int i;
 216        int err;
 217
 218        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
 219        if (err < 0)
 220                return err;
 221
 222        for (i = 0; i < params->count; ++i) {
 223                __be32 reg[2];
 224                struct amdtp_stream *stream;
 225                struct fw_iso_resources *resources;
 226                unsigned int pcm_cache;
 227                unsigned int pcm_chs;
 228                unsigned int midi_ports;
 229
 230                if (dir == AMDTP_IN_STREAM) {
 231                        stream = &dice->tx_stream[i];
 232                        resources = &dice->tx_resources[i];
 233
 234                        pcm_cache = dice->tx_pcm_chs[i][mode];
 235                        err = snd_dice_transaction_read_tx(dice,
 236                                        params->size * i + TX_NUMBER_AUDIO,
 237                                        reg, sizeof(reg));
 238                } else {
 239                        stream = &dice->rx_stream[i];
 240                        resources = &dice->rx_resources[i];
 241
 242                        pcm_cache = dice->rx_pcm_chs[i][mode];
 243                        err = snd_dice_transaction_read_rx(dice,
 244                                        params->size * i + RX_NUMBER_AUDIO,
 245                                        reg, sizeof(reg));
 246                }
 247                if (err < 0)
 248                        return err;
 249                pcm_chs = be32_to_cpu(reg[0]);
 250                midi_ports = be32_to_cpu(reg[1]);
 251
 252                // These are important for developer of this driver.
 253                if (pcm_chs != pcm_cache) {
 254                        dev_info(&dice->unit->device,
 255                                 "cache mismatch: pcm: %u:%u, midi: %u\n",
 256                                 pcm_chs, pcm_cache, midi_ports);
 257                        return -EPROTO;
 258                }
 259
 260                err = keep_resources(dice, stream, resources, rate, pcm_chs,
 261                                     midi_ports);
 262                if (err < 0)
 263                        return err;
 264        }
 265
 266        return 0;
 267}
 268
 269static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
 270                           struct reg_params *rx_params)
 271{
 272        stop_streams(dice, AMDTP_IN_STREAM, tx_params);
 273        stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
 274
 275        snd_dice_transaction_clear_enable(dice);
 276}
 277
 278int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
 279                                   unsigned int events_per_period,
 280                                   unsigned int events_per_buffer)
 281{
 282        unsigned int curr_rate;
 283        int err;
 284
 285        // Check sampling transmission frequency.
 286        err = snd_dice_transaction_get_rate(dice, &curr_rate);
 287        if (err < 0)
 288                return err;
 289        if (rate == 0)
 290                rate = curr_rate;
 291
 292        if (dice->substreams_counter == 0 || curr_rate != rate) {
 293                struct reg_params tx_params, rx_params;
 294
 295                amdtp_domain_stop(&dice->domain);
 296
 297                err = get_register_params(dice, &tx_params, &rx_params);
 298                if (err < 0)
 299                        return err;
 300                finish_session(dice, &tx_params, &rx_params);
 301
 302                release_resources(dice);
 303
 304                // Just after owning the unit (GLOBAL_OWNER), the unit can
 305                // return invalid stream formats. Selecting clock parameters
 306                // have an effect for the unit to refine it.
 307                err = ensure_phase_lock(dice, rate);
 308                if (err < 0)
 309                        return err;
 310
 311                // After changing sampling transfer frequency, the value of
 312                // register can be changed.
 313                err = get_register_params(dice, &tx_params, &rx_params);
 314                if (err < 0)
 315                        return err;
 316
 317                err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
 318                                          &tx_params);
 319                if (err < 0)
 320                        goto error;
 321
 322                err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
 323                                          &rx_params);
 324                if (err < 0)
 325                        goto error;
 326
 327                err = amdtp_domain_set_events_per_period(&dice->domain,
 328                                        events_per_period, events_per_buffer);
 329                if (err < 0)
 330                        goto error;
 331        }
 332
 333        return 0;
 334error:
 335        release_resources(dice);
 336        return err;
 337}
 338
 339static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
 340                         unsigned int rate, struct reg_params *params)
 341{
 342        unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
 343        int i;
 344        int err;
 345
 346        for (i = 0; i < params->count; i++) {
 347                struct amdtp_stream *stream;
 348                struct fw_iso_resources *resources;
 349                __be32 reg;
 350
 351                if (dir == AMDTP_IN_STREAM) {
 352                        stream = dice->tx_stream + i;
 353                        resources = dice->tx_resources + i;
 354                } else {
 355                        stream = dice->rx_stream + i;
 356                        resources = dice->rx_resources + i;
 357                }
 358
 359                reg = cpu_to_be32(resources->channel);
 360                if (dir == AMDTP_IN_STREAM) {
 361                        err = snd_dice_transaction_write_tx(dice,
 362                                        params->size * i + TX_ISOCHRONOUS,
 363                                        &reg, sizeof(reg));
 364                } else {
 365                        err = snd_dice_transaction_write_rx(dice,
 366                                        params->size * i + RX_ISOCHRONOUS,
 367                                        &reg, sizeof(reg));
 368                }
 369                if (err < 0)
 370                        return err;
 371
 372                if (dir == AMDTP_IN_STREAM) {
 373                        reg = cpu_to_be32(max_speed);
 374                        err = snd_dice_transaction_write_tx(dice,
 375                                        params->size * i + TX_SPEED,
 376                                        &reg, sizeof(reg));
 377                        if (err < 0)
 378                                return err;
 379                }
 380
 381                err = amdtp_domain_add_stream(&dice->domain, stream,
 382                                              resources->channel, max_speed);
 383                if (err < 0)
 384                        return err;
 385        }
 386
 387        return 0;
 388}
 389
 390/*
 391 * MEMO: After this function, there're two states of streams:
 392 *  - None streams are running.
 393 *  - All streams are running.
 394 */
 395int snd_dice_stream_start_duplex(struct snd_dice *dice)
 396{
 397        unsigned int generation = dice->rx_resources[0].generation;
 398        struct reg_params tx_params, rx_params;
 399        unsigned int i;
 400        unsigned int rate;
 401        enum snd_dice_rate_mode mode;
 402        int err;
 403
 404        if (dice->substreams_counter == 0)
 405                return -EIO;
 406
 407        err = get_register_params(dice, &tx_params, &rx_params);
 408        if (err < 0)
 409                return err;
 410
 411        // Check error of packet streaming.
 412        for (i = 0; i < MAX_STREAMS; ++i) {
 413                if (amdtp_streaming_error(&dice->tx_stream[i]) ||
 414                    amdtp_streaming_error(&dice->rx_stream[i])) {
 415                        amdtp_domain_stop(&dice->domain);
 416                        finish_session(dice, &tx_params, &rx_params);
 417                        break;
 418                }
 419        }
 420
 421        if (generation != fw_parent_device(dice->unit)->card->generation) {
 422                for (i = 0; i < MAX_STREAMS; ++i) {
 423                        if (i < tx_params.count)
 424                                fw_iso_resources_update(dice->tx_resources + i);
 425                        if (i < rx_params.count)
 426                                fw_iso_resources_update(dice->rx_resources + i);
 427                }
 428        }
 429
 430        // Check required streams are running or not.
 431        err = snd_dice_transaction_get_rate(dice, &rate);
 432        if (err < 0)
 433                return err;
 434        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
 435        if (err < 0)
 436                return err;
 437        for (i = 0; i < MAX_STREAMS; ++i) {
 438                if (dice->tx_pcm_chs[i][mode] > 0 &&
 439                    !amdtp_stream_running(&dice->tx_stream[i]))
 440                        break;
 441                if (dice->rx_pcm_chs[i][mode] > 0 &&
 442                    !amdtp_stream_running(&dice->rx_stream[i]))
 443                        break;
 444        }
 445        if (i < MAX_STREAMS) {
 446                // Start both streams.
 447                err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
 448                if (err < 0)
 449                        goto error;
 450
 451                err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
 452                if (err < 0)
 453                        goto error;
 454
 455                err = snd_dice_transaction_set_enable(dice);
 456                if (err < 0) {
 457                        dev_err(&dice->unit->device,
 458                                "fail to enable interface\n");
 459                        goto error;
 460                }
 461
 462                err = amdtp_domain_start(&dice->domain, 0);
 463                if (err < 0)
 464                        goto error;
 465
 466                for (i = 0; i < MAX_STREAMS; i++) {
 467                        if ((i < tx_params.count &&
 468                            !amdtp_stream_wait_callback(&dice->tx_stream[i],
 469                                                        CALLBACK_TIMEOUT)) ||
 470                            (i < rx_params.count &&
 471                             !amdtp_stream_wait_callback(&dice->rx_stream[i],
 472                                                         CALLBACK_TIMEOUT))) {
 473                                err = -ETIMEDOUT;
 474                                goto error;
 475                        }
 476                }
 477        }
 478
 479        return 0;
 480error:
 481        amdtp_domain_stop(&dice->domain);
 482        finish_session(dice, &tx_params, &rx_params);
 483        return err;
 484}
 485
 486/*
 487 * MEMO: After this function, there're two states of streams:
 488 *  - None streams are running.
 489 *  - All streams are running.
 490 */
 491void snd_dice_stream_stop_duplex(struct snd_dice *dice)
 492{
 493        struct reg_params tx_params, rx_params;
 494
 495        if (dice->substreams_counter == 0) {
 496                if (get_register_params(dice, &tx_params, &rx_params) >= 0) {
 497                        amdtp_domain_stop(&dice->domain);
 498                        finish_session(dice, &tx_params, &rx_params);
 499                }
 500
 501                release_resources(dice);
 502        }
 503}
 504
 505static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
 506                       unsigned int index)
 507{
 508        struct amdtp_stream *stream;
 509        struct fw_iso_resources *resources;
 510        int err;
 511
 512        if (dir == AMDTP_IN_STREAM) {
 513                stream = &dice->tx_stream[index];
 514                resources = &dice->tx_resources[index];
 515        } else {
 516                stream = &dice->rx_stream[index];
 517                resources = &dice->rx_resources[index];
 518        }
 519
 520        err = fw_iso_resources_init(resources, dice->unit);
 521        if (err < 0)
 522                goto end;
 523        resources->channels_mask = 0x00000000ffffffffuLL;
 524
 525        err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
 526        if (err < 0) {
 527                amdtp_stream_destroy(stream);
 528                fw_iso_resources_destroy(resources);
 529        }
 530end:
 531        return err;
 532}
 533
 534/*
 535 * This function should be called before starting streams or after stopping
 536 * streams.
 537 */
 538static void destroy_stream(struct snd_dice *dice,
 539                           enum amdtp_stream_direction dir,
 540                           unsigned int index)
 541{
 542        struct amdtp_stream *stream;
 543        struct fw_iso_resources *resources;
 544
 545        if (dir == AMDTP_IN_STREAM) {
 546                stream = &dice->tx_stream[index];
 547                resources = &dice->tx_resources[index];
 548        } else {
 549                stream = &dice->rx_stream[index];
 550                resources = &dice->rx_resources[index];
 551        }
 552
 553        amdtp_stream_destroy(stream);
 554        fw_iso_resources_destroy(resources);
 555}
 556
 557int snd_dice_stream_init_duplex(struct snd_dice *dice)
 558{
 559        int i, err;
 560
 561        for (i = 0; i < MAX_STREAMS; i++) {
 562                err = init_stream(dice, AMDTP_IN_STREAM, i);
 563                if (err < 0) {
 564                        for (; i >= 0; i--)
 565                                destroy_stream(dice, AMDTP_IN_STREAM, i);
 566                        goto end;
 567                }
 568        }
 569
 570        for (i = 0; i < MAX_STREAMS; i++) {
 571                err = init_stream(dice, AMDTP_OUT_STREAM, i);
 572                if (err < 0) {
 573                        for (; i >= 0; i--)
 574                                destroy_stream(dice, AMDTP_OUT_STREAM, i);
 575                        for (i = 0; i < MAX_STREAMS; i++)
 576                                destroy_stream(dice, AMDTP_IN_STREAM, i);
 577                        goto end;
 578                }
 579        }
 580
 581        err = amdtp_domain_init(&dice->domain);
 582        if (err < 0) {
 583                for (i = 0; i < MAX_STREAMS; ++i) {
 584                        destroy_stream(dice, AMDTP_OUT_STREAM, i);
 585                        destroy_stream(dice, AMDTP_IN_STREAM, i);
 586                }
 587        }
 588end:
 589        return err;
 590}
 591
 592void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 593{
 594        unsigned int i;
 595
 596        for (i = 0; i < MAX_STREAMS; i++) {
 597                destroy_stream(dice, AMDTP_IN_STREAM, i);
 598                destroy_stream(dice, AMDTP_OUT_STREAM, i);
 599        }
 600
 601        amdtp_domain_destroy(&dice->domain);
 602}
 603
 604void snd_dice_stream_update_duplex(struct snd_dice *dice)
 605{
 606        struct reg_params tx_params, rx_params;
 607
 608        /*
 609         * On a bus reset, the DICE firmware disables streaming and then goes
 610         * off contemplating its own navel for hundreds of milliseconds before
 611         * it can react to any of our attempts to reenable streaming.  This
 612         * means that we lose synchronization anyway, so we force our streams
 613         * to stop so that the application can restart them in an orderly
 614         * manner.
 615         */
 616        dice->global_enabled = false;
 617
 618        if (get_register_params(dice, &tx_params, &rx_params) == 0) {
 619                amdtp_domain_stop(&dice->domain);
 620
 621                stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
 622                stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
 623        }
 624}
 625
 626int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
 627{
 628        unsigned int rate;
 629        enum snd_dice_rate_mode mode;
 630        __be32 reg[2];
 631        struct reg_params tx_params, rx_params;
 632        int i;
 633        int err;
 634
 635        /* If extended protocol is available, detect detail spec. */
 636        err = snd_dice_detect_extension_formats(dice);
 637        if (err >= 0)
 638                return err;
 639
 640        /*
 641         * Available stream format is restricted at current mode of sampling
 642         * clock.
 643         */
 644        err = snd_dice_transaction_get_rate(dice, &rate);
 645        if (err < 0)
 646                return err;
 647
 648        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
 649        if (err < 0)
 650                return err;
 651
 652        /*
 653         * Just after owning the unit (GLOBAL_OWNER), the unit can return
 654         * invalid stream formats. Selecting clock parameters have an effect
 655         * for the unit to refine it.
 656         */
 657        err = ensure_phase_lock(dice, rate);
 658        if (err < 0)
 659                return err;
 660
 661        err = get_register_params(dice, &tx_params, &rx_params);
 662        if (err < 0)
 663                return err;
 664
 665        for (i = 0; i < tx_params.count; ++i) {
 666                err = snd_dice_transaction_read_tx(dice,
 667                                tx_params.size * i + TX_NUMBER_AUDIO,
 668                                reg, sizeof(reg));
 669                if (err < 0)
 670                        return err;
 671                dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
 672                dice->tx_midi_ports[i] = max_t(unsigned int,
 673                                be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
 674        }
 675        for (i = 0; i < rx_params.count; ++i) {
 676                err = snd_dice_transaction_read_rx(dice,
 677                                rx_params.size * i + RX_NUMBER_AUDIO,
 678                                reg, sizeof(reg));
 679                if (err < 0)
 680                        return err;
 681                dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
 682                dice->rx_midi_ports[i] = max_t(unsigned int,
 683                                be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
 684        }
 685
 686        return 0;
 687}
 688
 689static void dice_lock_changed(struct snd_dice *dice)
 690{
 691        dice->dev_lock_changed = true;
 692        wake_up(&dice->hwdep_wait);
 693}
 694
 695int snd_dice_stream_lock_try(struct snd_dice *dice)
 696{
 697        int err;
 698
 699        spin_lock_irq(&dice->lock);
 700
 701        if (dice->dev_lock_count < 0) {
 702                err = -EBUSY;
 703                goto out;
 704        }
 705
 706        if (dice->dev_lock_count++ == 0)
 707                dice_lock_changed(dice);
 708        err = 0;
 709out:
 710        spin_unlock_irq(&dice->lock);
 711        return err;
 712}
 713
 714void snd_dice_stream_lock_release(struct snd_dice *dice)
 715{
 716        spin_lock_irq(&dice->lock);
 717
 718        if (WARN_ON(dice->dev_lock_count <= 0))
 719                goto out;
 720
 721        if (--dice->dev_lock_count == 0)
 722                dice_lock_changed(dice);
 723out:
 724        spin_unlock_irq(&dice->lock);
 725}
 726