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                        amdtp_stream_stop(&dice->tx_stream[i]);
 158
 159                        snd_dice_transaction_write_tx(dice,
 160                                        params->size * i + TX_ISOCHRONOUS,
 161                                        &reg, sizeof(reg));
 162                } else {
 163                        amdtp_stream_stop(&dice->rx_stream[i]);
 164
 165                        snd_dice_transaction_write_rx(dice,
 166                                        params->size * i + RX_ISOCHRONOUS,
 167                                        &reg, sizeof(reg));
 168                }
 169        }
 170}
 171
 172static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
 173                          struct fw_iso_resources *resources, unsigned int rate,
 174                          unsigned int pcm_chs, unsigned int midi_ports)
 175{
 176        bool double_pcm_frames;
 177        unsigned int i;
 178        int err;
 179
 180        // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
 181        // one data block of AMDTP packet. Thus sampling transfer frequency is
 182        // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
 183        // transferred on AMDTP packets at 96 kHz. Two successive samples of a
 184        // channel are stored consecutively in the packet. This quirk is called
 185        // as 'Dual Wire'.
 186        // For this quirk, blocking mode is required and PCM buffer size should
 187        // be aligned to SYT_INTERVAL.
 188        double_pcm_frames = rate > 96000;
 189        if (double_pcm_frames) {
 190                rate /= 2;
 191                pcm_chs *= 2;
 192        }
 193
 194        err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
 195                                         double_pcm_frames);
 196        if (err < 0)
 197                return err;
 198
 199        if (double_pcm_frames) {
 200                pcm_chs /= 2;
 201
 202                for (i = 0; i < pcm_chs; i++) {
 203                        amdtp_am824_set_pcm_position(stream, i, i * 2);
 204                        amdtp_am824_set_pcm_position(stream, i + pcm_chs,
 205                                                     i * 2 + 1);
 206                }
 207        }
 208
 209        return fw_iso_resources_allocate(resources,
 210                                amdtp_stream_get_max_payload(stream),
 211                                fw_parent_device(dice->unit)->max_speed);
 212}
 213
 214static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
 215                               enum amdtp_stream_direction dir,
 216                               struct reg_params *params)
 217{
 218        enum snd_dice_rate_mode mode;
 219        int i;
 220        int err;
 221
 222        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
 223        if (err < 0)
 224                return err;
 225
 226        for (i = 0; i < params->count; ++i) {
 227                __be32 reg[2];
 228                struct amdtp_stream *stream;
 229                struct fw_iso_resources *resources;
 230                unsigned int pcm_cache;
 231                unsigned int midi_cache;
 232                unsigned int pcm_chs;
 233                unsigned int midi_ports;
 234
 235                if (dir == AMDTP_IN_STREAM) {
 236                        stream = &dice->tx_stream[i];
 237                        resources = &dice->tx_resources[i];
 238
 239                        pcm_cache = dice->tx_pcm_chs[i][mode];
 240                        midi_cache = dice->tx_midi_ports[i];
 241                        err = snd_dice_transaction_read_tx(dice,
 242                                        params->size * i + TX_NUMBER_AUDIO,
 243                                        reg, sizeof(reg));
 244                } else {
 245                        stream = &dice->rx_stream[i];
 246                        resources = &dice->rx_resources[i];
 247
 248                        pcm_cache = dice->rx_pcm_chs[i][mode];
 249                        midi_cache = dice->rx_midi_ports[i];
 250                        err = snd_dice_transaction_read_rx(dice,
 251                                        params->size * i + RX_NUMBER_AUDIO,
 252                                        reg, sizeof(reg));
 253                }
 254                if (err < 0)
 255                        return err;
 256                pcm_chs = be32_to_cpu(reg[0]);
 257                midi_ports = be32_to_cpu(reg[1]);
 258
 259                // These are important for developer of this driver.
 260                if (pcm_chs != pcm_cache || midi_ports != midi_cache) {
 261                        dev_info(&dice->unit->device,
 262                                 "cache mismatch: pcm: %u:%u, midi: %u:%u\n",
 263                                 pcm_chs, pcm_cache, midi_ports, midi_cache);
 264                        return -EPROTO;
 265                }
 266
 267                err = keep_resources(dice, stream, resources, rate, pcm_chs,
 268                                     midi_ports);
 269                if (err < 0)
 270                        return err;
 271        }
 272
 273        return 0;
 274}
 275
 276static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
 277                           struct reg_params *rx_params)
 278{
 279        stop_streams(dice, AMDTP_IN_STREAM, tx_params);
 280        stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
 281
 282        snd_dice_transaction_clear_enable(dice);
 283}
 284
 285int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate)
 286{
 287        unsigned int curr_rate;
 288        int err;
 289
 290        // Check sampling transmission frequency.
 291        err = snd_dice_transaction_get_rate(dice, &curr_rate);
 292        if (err < 0)
 293                return err;
 294        if (rate == 0)
 295                rate = curr_rate;
 296
 297        if (dice->substreams_counter == 0 || curr_rate != rate) {
 298                struct reg_params tx_params, rx_params;
 299
 300                err = get_register_params(dice, &tx_params, &rx_params);
 301                if (err < 0)
 302                        return err;
 303
 304                finish_session(dice, &tx_params, &rx_params);
 305
 306                release_resources(dice);
 307
 308                // Just after owning the unit (GLOBAL_OWNER), the unit can
 309                // return invalid stream formats. Selecting clock parameters
 310                // have an effect for the unit to refine it.
 311                err = ensure_phase_lock(dice, rate);
 312                if (err < 0)
 313                        return err;
 314
 315                // After changing sampling transfer frequency, the value of
 316                // register can be changed.
 317                err = get_register_params(dice, &tx_params, &rx_params);
 318                if (err < 0)
 319                        return err;
 320
 321                err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
 322                                          &tx_params);
 323                if (err < 0)
 324                        goto error;
 325
 326                err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
 327                                          &rx_params);
 328                if (err < 0)
 329                        goto error;
 330        }
 331
 332        return 0;
 333error:
 334        release_resources(dice);
 335        return err;
 336}
 337
 338static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
 339                         unsigned int rate, struct reg_params *params)
 340{
 341        unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
 342        int i;
 343        int err;
 344
 345        for (i = 0; i < params->count; i++) {
 346                struct amdtp_stream *stream;
 347                struct fw_iso_resources *resources;
 348                __be32 reg;
 349
 350                if (dir == AMDTP_IN_STREAM) {
 351                        stream = dice->tx_stream + i;
 352                        resources = dice->tx_resources + i;
 353                } else {
 354                        stream = dice->rx_stream + i;
 355                        resources = dice->rx_resources + i;
 356                }
 357
 358                reg = cpu_to_be32(resources->channel);
 359                if (dir == AMDTP_IN_STREAM) {
 360                        err = snd_dice_transaction_write_tx(dice,
 361                                        params->size * i + TX_ISOCHRONOUS,
 362                                        &reg, sizeof(reg));
 363                } else {
 364                        err = snd_dice_transaction_write_rx(dice,
 365                                        params->size * i + RX_ISOCHRONOUS,
 366                                        &reg, sizeof(reg));
 367                }
 368                if (err < 0)
 369                        return err;
 370
 371                if (dir == AMDTP_IN_STREAM) {
 372                        reg = cpu_to_be32(max_speed);
 373                        err = snd_dice_transaction_write_tx(dice,
 374                                        params->size * i + TX_SPEED,
 375                                        &reg, sizeof(reg));
 376                        if (err < 0)
 377                                return err;
 378                }
 379
 380                err = amdtp_stream_start(stream, resources->channel, max_speed);
 381                if (err < 0)
 382                        return err;
 383        }
 384
 385        return 0;
 386}
 387
 388/*
 389 * MEMO: After this function, there're two states of streams:
 390 *  - None streams are running.
 391 *  - All streams are running.
 392 */
 393int snd_dice_stream_start_duplex(struct snd_dice *dice)
 394{
 395        unsigned int generation = dice->rx_resources[0].generation;
 396        struct reg_params tx_params, rx_params;
 397        unsigned int i;
 398        unsigned int rate;
 399        enum snd_dice_rate_mode mode;
 400        int err;
 401
 402        if (dice->substreams_counter == 0)
 403                return -EIO;
 404
 405        err = get_register_params(dice, &tx_params, &rx_params);
 406        if (err < 0)
 407                return err;
 408
 409        // Check error of packet streaming.
 410        for (i = 0; i < MAX_STREAMS; ++i) {
 411                if (amdtp_streaming_error(&dice->tx_stream[i]) ||
 412                    amdtp_streaming_error(&dice->rx_stream[i])) {
 413                        finish_session(dice, &tx_params, &rx_params);
 414                        break;
 415                }
 416        }
 417
 418        if (generation != fw_parent_device(dice->unit)->card->generation) {
 419                for (i = 0; i < MAX_STREAMS; ++i) {
 420                        if (i < tx_params.count)
 421                                fw_iso_resources_update(dice->tx_resources + i);
 422                        if (i < rx_params.count)
 423                                fw_iso_resources_update(dice->rx_resources + i);
 424                }
 425        }
 426
 427        // Check required streams are running or not.
 428        err = snd_dice_transaction_get_rate(dice, &rate);
 429        if (err < 0)
 430                return err;
 431        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
 432        if (err < 0)
 433                return err;
 434        for (i = 0; i < MAX_STREAMS; ++i) {
 435                if (dice->tx_pcm_chs[i][mode] > 0 &&
 436                    !amdtp_stream_running(&dice->tx_stream[i]))
 437                        break;
 438                if (dice->rx_pcm_chs[i][mode] > 0 &&
 439                    !amdtp_stream_running(&dice->rx_stream[i]))
 440                        break;
 441        }
 442        if (i < MAX_STREAMS) {
 443                // Start both streams.
 444                err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
 445                if (err < 0)
 446                        goto error;
 447
 448                err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
 449                if (err < 0)
 450                        goto error;
 451
 452                err = snd_dice_transaction_set_enable(dice);
 453                if (err < 0) {
 454                        dev_err(&dice->unit->device,
 455                                "fail to enable interface\n");
 456                        goto error;
 457                }
 458
 459                for (i = 0; i < MAX_STREAMS; i++) {
 460                        if ((i < tx_params.count &&
 461                            !amdtp_stream_wait_callback(&dice->tx_stream[i],
 462                                                        CALLBACK_TIMEOUT)) ||
 463                            (i < rx_params.count &&
 464                             !amdtp_stream_wait_callback(&dice->rx_stream[i],
 465                                                         CALLBACK_TIMEOUT))) {
 466                                err = -ETIMEDOUT;
 467                                goto error;
 468                        }
 469                }
 470        }
 471
 472        return 0;
 473error:
 474        finish_session(dice, &tx_params, &rx_params);
 475        return err;
 476}
 477
 478/*
 479 * MEMO: After this function, there're two states of streams:
 480 *  - None streams are running.
 481 *  - All streams are running.
 482 */
 483void snd_dice_stream_stop_duplex(struct snd_dice *dice)
 484{
 485        struct reg_params tx_params, rx_params;
 486
 487        if (dice->substreams_counter == 0) {
 488                if (get_register_params(dice, &tx_params, &rx_params) >= 0)
 489                        finish_session(dice, &tx_params, &rx_params);
 490
 491                release_resources(dice);
 492        }
 493}
 494
 495static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
 496                       unsigned int index)
 497{
 498        struct amdtp_stream *stream;
 499        struct fw_iso_resources *resources;
 500        int err;
 501
 502        if (dir == AMDTP_IN_STREAM) {
 503                stream = &dice->tx_stream[index];
 504                resources = &dice->tx_resources[index];
 505        } else {
 506                stream = &dice->rx_stream[index];
 507                resources = &dice->rx_resources[index];
 508        }
 509
 510        err = fw_iso_resources_init(resources, dice->unit);
 511        if (err < 0)
 512                goto end;
 513        resources->channels_mask = 0x00000000ffffffffuLL;
 514
 515        err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
 516        if (err < 0) {
 517                amdtp_stream_destroy(stream);
 518                fw_iso_resources_destroy(resources);
 519        }
 520end:
 521        return err;
 522}
 523
 524/*
 525 * This function should be called before starting streams or after stopping
 526 * streams.
 527 */
 528static void destroy_stream(struct snd_dice *dice,
 529                           enum amdtp_stream_direction dir,
 530                           unsigned int index)
 531{
 532        struct amdtp_stream *stream;
 533        struct fw_iso_resources *resources;
 534
 535        if (dir == AMDTP_IN_STREAM) {
 536                stream = &dice->tx_stream[index];
 537                resources = &dice->tx_resources[index];
 538        } else {
 539                stream = &dice->rx_stream[index];
 540                resources = &dice->rx_resources[index];
 541        }
 542
 543        amdtp_stream_destroy(stream);
 544        fw_iso_resources_destroy(resources);
 545}
 546
 547int snd_dice_stream_init_duplex(struct snd_dice *dice)
 548{
 549        int i, err;
 550
 551        for (i = 0; i < MAX_STREAMS; i++) {
 552                err = init_stream(dice, AMDTP_IN_STREAM, i);
 553                if (err < 0) {
 554                        for (; i >= 0; i--)
 555                                destroy_stream(dice, AMDTP_IN_STREAM, i);
 556                        goto end;
 557                }
 558        }
 559
 560        for (i = 0; i < MAX_STREAMS; i++) {
 561                err = init_stream(dice, AMDTP_OUT_STREAM, i);
 562                if (err < 0) {
 563                        for (; i >= 0; i--)
 564                                destroy_stream(dice, AMDTP_OUT_STREAM, i);
 565                        for (i = 0; i < MAX_STREAMS; i++)
 566                                destroy_stream(dice, AMDTP_IN_STREAM, i);
 567                        break;
 568                }
 569        }
 570end:
 571        return err;
 572}
 573
 574void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 575{
 576        unsigned int i;
 577
 578        for (i = 0; i < MAX_STREAMS; i++) {
 579                destroy_stream(dice, AMDTP_IN_STREAM, i);
 580                destroy_stream(dice, AMDTP_OUT_STREAM, i);
 581        }
 582}
 583
 584void snd_dice_stream_update_duplex(struct snd_dice *dice)
 585{
 586        struct reg_params tx_params, rx_params;
 587
 588        /*
 589         * On a bus reset, the DICE firmware disables streaming and then goes
 590         * off contemplating its own navel for hundreds of milliseconds before
 591         * it can react to any of our attempts to reenable streaming.  This
 592         * means that we lose synchronization anyway, so we force our streams
 593         * to stop so that the application can restart them in an orderly
 594         * manner.
 595         */
 596        dice->global_enabled = false;
 597
 598        if (get_register_params(dice, &tx_params, &rx_params) == 0) {
 599                stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
 600                stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
 601        }
 602}
 603
 604int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
 605{
 606        unsigned int rate;
 607        enum snd_dice_rate_mode mode;
 608        __be32 reg[2];
 609        struct reg_params tx_params, rx_params;
 610        int i;
 611        int err;
 612
 613        /* If extended protocol is available, detect detail spec. */
 614        err = snd_dice_detect_extension_formats(dice);
 615        if (err >= 0)
 616                return err;
 617
 618        /*
 619         * Available stream format is restricted at current mode of sampling
 620         * clock.
 621         */
 622        err = snd_dice_transaction_get_rate(dice, &rate);
 623        if (err < 0)
 624                return err;
 625
 626        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
 627        if (err < 0)
 628                return err;
 629
 630        /*
 631         * Just after owning the unit (GLOBAL_OWNER), the unit can return
 632         * invalid stream formats. Selecting clock parameters have an effect
 633         * for the unit to refine it.
 634         */
 635        err = ensure_phase_lock(dice, rate);
 636        if (err < 0)
 637                return err;
 638
 639        err = get_register_params(dice, &tx_params, &rx_params);
 640        if (err < 0)
 641                return err;
 642
 643        for (i = 0; i < tx_params.count; ++i) {
 644                err = snd_dice_transaction_read_tx(dice,
 645                                tx_params.size * i + TX_NUMBER_AUDIO,
 646                                reg, sizeof(reg));
 647                if (err < 0)
 648                        return err;
 649                dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
 650                dice->tx_midi_ports[i] = max_t(unsigned int,
 651                                be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
 652        }
 653        for (i = 0; i < rx_params.count; ++i) {
 654                err = snd_dice_transaction_read_rx(dice,
 655                                rx_params.size * i + RX_NUMBER_AUDIO,
 656                                reg, sizeof(reg));
 657                if (err < 0)
 658                        return err;
 659                dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
 660                dice->rx_midi_ports[i] = max_t(unsigned int,
 661                                be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
 662        }
 663
 664        return 0;
 665}
 666
 667static void dice_lock_changed(struct snd_dice *dice)
 668{
 669        dice->dev_lock_changed = true;
 670        wake_up(&dice->hwdep_wait);
 671}
 672
 673int snd_dice_stream_lock_try(struct snd_dice *dice)
 674{
 675        int err;
 676
 677        spin_lock_irq(&dice->lock);
 678
 679        if (dice->dev_lock_count < 0) {
 680                err = -EBUSY;
 681                goto out;
 682        }
 683
 684        if (dice->dev_lock_count++ == 0)
 685                dice_lock_changed(dice);
 686        err = 0;
 687out:
 688        spin_unlock_irq(&dice->lock);
 689        return err;
 690}
 691
 692void snd_dice_stream_lock_release(struct snd_dice *dice)
 693{
 694        spin_lock_irq(&dice->lock);
 695
 696        if (WARN_ON(dice->dev_lock_count <= 0))
 697                goto out;
 698
 699        if (--dice->dev_lock_count == 0)
 700                dice_lock_changed(dice);
 701out:
 702        spin_unlock_irq(&dice->lock);
 703}
 704