Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * dice_stream.c - a part of driver for DICE based devices
0004  *
0005  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
0006  * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
0007  */
0008 
0009 #include "dice.h"
0010 
0011 #define READY_TIMEOUT_MS    200
0012 #define NOTIFICATION_TIMEOUT_MS 100
0013 
0014 struct reg_params {
0015     unsigned int count;
0016     unsigned int size;
0017 };
0018 
0019 const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
0020     /* mode 0 */
0021     [0] =  32000,
0022     [1] =  44100,
0023     [2] =  48000,
0024     /* mode 1 */
0025     [3] =  88200,
0026     [4] =  96000,
0027     /* mode 2 */
0028     [5] = 176400,
0029     [6] = 192000,
0030 };
0031 
0032 int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
0033                   enum snd_dice_rate_mode *mode)
0034 {
0035     /* Corresponding to each entry in snd_dice_rates. */
0036     static const enum snd_dice_rate_mode modes[] = {
0037         [0] = SND_DICE_RATE_MODE_LOW,
0038         [1] = SND_DICE_RATE_MODE_LOW,
0039         [2] = SND_DICE_RATE_MODE_LOW,
0040         [3] = SND_DICE_RATE_MODE_MIDDLE,
0041         [4] = SND_DICE_RATE_MODE_MIDDLE,
0042         [5] = SND_DICE_RATE_MODE_HIGH,
0043         [6] = SND_DICE_RATE_MODE_HIGH,
0044     };
0045     int i;
0046 
0047     for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
0048         if (!(dice->clock_caps & BIT(i)))
0049             continue;
0050         if (snd_dice_rates[i] != rate)
0051             continue;
0052 
0053         *mode = modes[i];
0054         return 0;
0055     }
0056 
0057     return -EINVAL;
0058 }
0059 
0060 static int select_clock(struct snd_dice *dice, unsigned int rate)
0061 {
0062     __be32 reg;
0063     u32 data;
0064     int i;
0065     int err;
0066 
0067     err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
0068                            &reg, sizeof(reg));
0069     if (err < 0)
0070         return err;
0071 
0072     data = be32_to_cpu(reg);
0073 
0074     data &= ~CLOCK_RATE_MASK;
0075     for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
0076         if (snd_dice_rates[i] == rate)
0077             break;
0078     }
0079     if (i == ARRAY_SIZE(snd_dice_rates))
0080         return -EINVAL;
0081     data |= i << CLOCK_RATE_SHIFT;
0082 
0083     if (completion_done(&dice->clock_accepted))
0084         reinit_completion(&dice->clock_accepted);
0085 
0086     reg = cpu_to_be32(data);
0087     err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
0088                         &reg, sizeof(reg));
0089     if (err < 0)
0090         return err;
0091 
0092     if (wait_for_completion_timeout(&dice->clock_accepted,
0093             msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
0094         return -ETIMEDOUT;
0095 
0096     return 0;
0097 }
0098 
0099 static int get_register_params(struct snd_dice *dice,
0100                    struct reg_params *tx_params,
0101                    struct reg_params *rx_params)
0102 {
0103     __be32 reg[2];
0104     int err;
0105 
0106     err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
0107     if (err < 0)
0108         return err;
0109     tx_params->count =
0110             min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
0111     tx_params->size = be32_to_cpu(reg[1]) * 4;
0112 
0113     err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
0114     if (err < 0)
0115         return err;
0116     rx_params->count =
0117             min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
0118     rx_params->size = be32_to_cpu(reg[1]) * 4;
0119 
0120     return 0;
0121 }
0122 
0123 static void release_resources(struct snd_dice *dice)
0124 {
0125     int i;
0126 
0127     for (i = 0; i < MAX_STREAMS; ++i) {
0128         fw_iso_resources_free(&dice->tx_resources[i]);
0129         fw_iso_resources_free(&dice->rx_resources[i]);
0130     }
0131 }
0132 
0133 static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
0134              struct reg_params *params)
0135 {
0136     __be32 reg;
0137     unsigned int i;
0138 
0139     for (i = 0; i < params->count; i++) {
0140         reg = cpu_to_be32((u32)-1);
0141         if (dir == AMDTP_IN_STREAM) {
0142             snd_dice_transaction_write_tx(dice,
0143                     params->size * i + TX_ISOCHRONOUS,
0144                     &reg, sizeof(reg));
0145         } else {
0146             snd_dice_transaction_write_rx(dice,
0147                     params->size * i + RX_ISOCHRONOUS,
0148                     &reg, sizeof(reg));
0149         }
0150     }
0151 }
0152 
0153 static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
0154               struct fw_iso_resources *resources, unsigned int rate,
0155               unsigned int pcm_chs, unsigned int midi_ports)
0156 {
0157     bool double_pcm_frames;
0158     unsigned int i;
0159     int err;
0160 
0161     // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
0162     // one data block of AMDTP packet. Thus sampling transfer frequency is
0163     // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
0164     // transferred on AMDTP packets at 96 kHz. Two successive samples of a
0165     // channel are stored consecutively in the packet. This quirk is called
0166     // as 'Dual Wire'.
0167     // For this quirk, blocking mode is required and PCM buffer size should
0168     // be aligned to SYT_INTERVAL.
0169     double_pcm_frames = (rate > 96000 && !dice->disable_double_pcm_frames);
0170     if (double_pcm_frames) {
0171         rate /= 2;
0172         pcm_chs *= 2;
0173     }
0174 
0175     err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
0176                      double_pcm_frames);
0177     if (err < 0)
0178         return err;
0179 
0180     if (double_pcm_frames) {
0181         pcm_chs /= 2;
0182 
0183         for (i = 0; i < pcm_chs; i++) {
0184             amdtp_am824_set_pcm_position(stream, i, i * 2);
0185             amdtp_am824_set_pcm_position(stream, i + pcm_chs,
0186                              i * 2 + 1);
0187         }
0188     }
0189 
0190     return fw_iso_resources_allocate(resources,
0191                 amdtp_stream_get_max_payload(stream),
0192                 fw_parent_device(dice->unit)->max_speed);
0193 }
0194 
0195 static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
0196                    enum amdtp_stream_direction dir,
0197                    struct reg_params *params)
0198 {
0199     enum snd_dice_rate_mode mode;
0200     int i;
0201     int err;
0202 
0203     err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
0204     if (err < 0)
0205         return err;
0206 
0207     for (i = 0; i < params->count; ++i) {
0208         __be32 reg[2];
0209         struct amdtp_stream *stream;
0210         struct fw_iso_resources *resources;
0211         unsigned int pcm_cache;
0212         unsigned int pcm_chs;
0213         unsigned int midi_ports;
0214 
0215         if (dir == AMDTP_IN_STREAM) {
0216             stream = &dice->tx_stream[i];
0217             resources = &dice->tx_resources[i];
0218 
0219             pcm_cache = dice->tx_pcm_chs[i][mode];
0220             err = snd_dice_transaction_read_tx(dice,
0221                     params->size * i + TX_NUMBER_AUDIO,
0222                     reg, sizeof(reg));
0223         } else {
0224             stream = &dice->rx_stream[i];
0225             resources = &dice->rx_resources[i];
0226 
0227             pcm_cache = dice->rx_pcm_chs[i][mode];
0228             err = snd_dice_transaction_read_rx(dice,
0229                     params->size * i + RX_NUMBER_AUDIO,
0230                     reg, sizeof(reg));
0231         }
0232         if (err < 0)
0233             return err;
0234         pcm_chs = be32_to_cpu(reg[0]);
0235         midi_ports = be32_to_cpu(reg[1]);
0236 
0237         // These are important for developer of this driver.
0238         if (pcm_chs != pcm_cache) {
0239             dev_info(&dice->unit->device,
0240                  "cache mismatch: pcm: %u:%u, midi: %u\n",
0241                  pcm_chs, pcm_cache, midi_ports);
0242             return -EPROTO;
0243         }
0244 
0245         err = keep_resources(dice, stream, resources, rate, pcm_chs,
0246                      midi_ports);
0247         if (err < 0)
0248             return err;
0249     }
0250 
0251     return 0;
0252 }
0253 
0254 static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
0255                struct reg_params *rx_params)
0256 {
0257     stop_streams(dice, AMDTP_IN_STREAM, tx_params);
0258     stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
0259 
0260     snd_dice_transaction_clear_enable(dice);
0261 }
0262 
0263 int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
0264                    unsigned int events_per_period,
0265                    unsigned int events_per_buffer)
0266 {
0267     unsigned int curr_rate;
0268     int err;
0269 
0270     // Check sampling transmission frequency.
0271     err = snd_dice_transaction_get_rate(dice, &curr_rate);
0272     if (err < 0)
0273         return err;
0274     if (rate == 0)
0275         rate = curr_rate;
0276 
0277     if (dice->substreams_counter == 0 || curr_rate != rate) {
0278         struct reg_params tx_params, rx_params;
0279 
0280         amdtp_domain_stop(&dice->domain);
0281 
0282         err = get_register_params(dice, &tx_params, &rx_params);
0283         if (err < 0)
0284             return err;
0285         finish_session(dice, &tx_params, &rx_params);
0286 
0287         release_resources(dice);
0288 
0289         // Just after owning the unit (GLOBAL_OWNER), the unit can
0290         // return invalid stream formats. Selecting clock parameters
0291         // have an effect for the unit to refine it.
0292         err = select_clock(dice, rate);
0293         if (err < 0)
0294             return err;
0295 
0296         // After changing sampling transfer frequency, the value of
0297         // register can be changed.
0298         err = get_register_params(dice, &tx_params, &rx_params);
0299         if (err < 0)
0300             return err;
0301 
0302         err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
0303                       &tx_params);
0304         if (err < 0)
0305             goto error;
0306 
0307         err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
0308                       &rx_params);
0309         if (err < 0)
0310             goto error;
0311 
0312         err = amdtp_domain_set_events_per_period(&dice->domain,
0313                     events_per_period, events_per_buffer);
0314         if (err < 0)
0315             goto error;
0316     }
0317 
0318     return 0;
0319 error:
0320     release_resources(dice);
0321     return err;
0322 }
0323 
0324 static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
0325              unsigned int rate, struct reg_params *params)
0326 {
0327     unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
0328     int i;
0329     int err;
0330 
0331     for (i = 0; i < params->count; i++) {
0332         struct amdtp_stream *stream;
0333         struct fw_iso_resources *resources;
0334         __be32 reg;
0335 
0336         if (dir == AMDTP_IN_STREAM) {
0337             stream = dice->tx_stream + i;
0338             resources = dice->tx_resources + i;
0339         } else {
0340             stream = dice->rx_stream + i;
0341             resources = dice->rx_resources + i;
0342         }
0343 
0344         reg = cpu_to_be32(resources->channel);
0345         if (dir == AMDTP_IN_STREAM) {
0346             err = snd_dice_transaction_write_tx(dice,
0347                     params->size * i + TX_ISOCHRONOUS,
0348                     &reg, sizeof(reg));
0349         } else {
0350             err = snd_dice_transaction_write_rx(dice,
0351                     params->size * i + RX_ISOCHRONOUS,
0352                     &reg, sizeof(reg));
0353         }
0354         if (err < 0)
0355             return err;
0356 
0357         if (dir == AMDTP_IN_STREAM) {
0358             reg = cpu_to_be32(max_speed);
0359             err = snd_dice_transaction_write_tx(dice,
0360                     params->size * i + TX_SPEED,
0361                     &reg, sizeof(reg));
0362             if (err < 0)
0363                 return err;
0364         }
0365 
0366         err = amdtp_domain_add_stream(&dice->domain, stream,
0367                           resources->channel, max_speed);
0368         if (err < 0)
0369             return err;
0370     }
0371 
0372     return 0;
0373 }
0374 
0375 /*
0376  * MEMO: After this function, there're two states of streams:
0377  *  - None streams are running.
0378  *  - All streams are running.
0379  */
0380 int snd_dice_stream_start_duplex(struct snd_dice *dice)
0381 {
0382     unsigned int generation = dice->rx_resources[0].generation;
0383     struct reg_params tx_params, rx_params;
0384     unsigned int i;
0385     unsigned int rate;
0386     enum snd_dice_rate_mode mode;
0387     int err;
0388 
0389     if (dice->substreams_counter == 0)
0390         return -EIO;
0391 
0392     err = get_register_params(dice, &tx_params, &rx_params);
0393     if (err < 0)
0394         return err;
0395 
0396     // Check error of packet streaming.
0397     for (i = 0; i < MAX_STREAMS; ++i) {
0398         if (amdtp_streaming_error(&dice->tx_stream[i]) ||
0399             amdtp_streaming_error(&dice->rx_stream[i])) {
0400             amdtp_domain_stop(&dice->domain);
0401             finish_session(dice, &tx_params, &rx_params);
0402             break;
0403         }
0404     }
0405 
0406     if (generation != fw_parent_device(dice->unit)->card->generation) {
0407         for (i = 0; i < MAX_STREAMS; ++i) {
0408             if (i < tx_params.count)
0409                 fw_iso_resources_update(dice->tx_resources + i);
0410             if (i < rx_params.count)
0411                 fw_iso_resources_update(dice->rx_resources + i);
0412         }
0413     }
0414 
0415     // Check required streams are running or not.
0416     err = snd_dice_transaction_get_rate(dice, &rate);
0417     if (err < 0)
0418         return err;
0419     err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
0420     if (err < 0)
0421         return err;
0422     for (i = 0; i < MAX_STREAMS; ++i) {
0423         if (dice->tx_pcm_chs[i][mode] > 0 &&
0424             !amdtp_stream_running(&dice->tx_stream[i]))
0425             break;
0426         if (dice->rx_pcm_chs[i][mode] > 0 &&
0427             !amdtp_stream_running(&dice->rx_stream[i]))
0428             break;
0429     }
0430     if (i < MAX_STREAMS) {
0431         // Start both streams.
0432         err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
0433         if (err < 0)
0434             goto error;
0435 
0436         err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
0437         if (err < 0)
0438             goto error;
0439 
0440         err = snd_dice_transaction_set_enable(dice);
0441         if (err < 0) {
0442             dev_err(&dice->unit->device,
0443                 "fail to enable interface\n");
0444             goto error;
0445         }
0446 
0447         // MEMO: The device immediately starts packet transmission when enabled. Some
0448         // devices are strictly to generate any discontinuity in the sequence of tx packet
0449         // when they receives invalid sequence of presentation time in CIP header. The
0450         // sequence replay for media clock recovery can suppress the behaviour.
0451         err = amdtp_domain_start(&dice->domain, 0, true, false);
0452         if (err < 0)
0453             goto error;
0454 
0455         if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) {
0456             err = -ETIMEDOUT;
0457             goto error;
0458         }
0459     }
0460 
0461     return 0;
0462 error:
0463     amdtp_domain_stop(&dice->domain);
0464     finish_session(dice, &tx_params, &rx_params);
0465     return err;
0466 }
0467 
0468 /*
0469  * MEMO: After this function, there're two states of streams:
0470  *  - None streams are running.
0471  *  - All streams are running.
0472  */
0473 void snd_dice_stream_stop_duplex(struct snd_dice *dice)
0474 {
0475     struct reg_params tx_params, rx_params;
0476 
0477     if (dice->substreams_counter == 0) {
0478         if (get_register_params(dice, &tx_params, &rx_params) >= 0)
0479             finish_session(dice, &tx_params, &rx_params);
0480 
0481         amdtp_domain_stop(&dice->domain);
0482         release_resources(dice);
0483     }
0484 }
0485 
0486 static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
0487                unsigned int index)
0488 {
0489     struct amdtp_stream *stream;
0490     struct fw_iso_resources *resources;
0491     int err;
0492 
0493     if (dir == AMDTP_IN_STREAM) {
0494         stream = &dice->tx_stream[index];
0495         resources = &dice->tx_resources[index];
0496     } else {
0497         stream = &dice->rx_stream[index];
0498         resources = &dice->rx_resources[index];
0499     }
0500 
0501     err = fw_iso_resources_init(resources, dice->unit);
0502     if (err < 0)
0503         goto end;
0504     resources->channels_mask = 0x00000000ffffffffuLL;
0505 
0506     err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
0507     if (err < 0) {
0508         amdtp_stream_destroy(stream);
0509         fw_iso_resources_destroy(resources);
0510     }
0511 end:
0512     return err;
0513 }
0514 
0515 /*
0516  * This function should be called before starting streams or after stopping
0517  * streams.
0518  */
0519 static void destroy_stream(struct snd_dice *dice,
0520                enum amdtp_stream_direction dir,
0521                unsigned int index)
0522 {
0523     struct amdtp_stream *stream;
0524     struct fw_iso_resources *resources;
0525 
0526     if (dir == AMDTP_IN_STREAM) {
0527         stream = &dice->tx_stream[index];
0528         resources = &dice->tx_resources[index];
0529     } else {
0530         stream = &dice->rx_stream[index];
0531         resources = &dice->rx_resources[index];
0532     }
0533 
0534     amdtp_stream_destroy(stream);
0535     fw_iso_resources_destroy(resources);
0536 }
0537 
0538 int snd_dice_stream_init_duplex(struct snd_dice *dice)
0539 {
0540     int i, err;
0541 
0542     for (i = 0; i < MAX_STREAMS; i++) {
0543         err = init_stream(dice, AMDTP_IN_STREAM, i);
0544         if (err < 0) {
0545             for (; i >= 0; i--)
0546                 destroy_stream(dice, AMDTP_IN_STREAM, i);
0547             goto end;
0548         }
0549     }
0550 
0551     for (i = 0; i < MAX_STREAMS; i++) {
0552         err = init_stream(dice, AMDTP_OUT_STREAM, i);
0553         if (err < 0) {
0554             for (; i >= 0; i--)
0555                 destroy_stream(dice, AMDTP_OUT_STREAM, i);
0556             for (i = 0; i < MAX_STREAMS; i++)
0557                 destroy_stream(dice, AMDTP_IN_STREAM, i);
0558             goto end;
0559         }
0560     }
0561 
0562     err = amdtp_domain_init(&dice->domain);
0563     if (err < 0) {
0564         for (i = 0; i < MAX_STREAMS; ++i) {
0565             destroy_stream(dice, AMDTP_OUT_STREAM, i);
0566             destroy_stream(dice, AMDTP_IN_STREAM, i);
0567         }
0568     }
0569 end:
0570     return err;
0571 }
0572 
0573 void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
0574 {
0575     unsigned int i;
0576 
0577     for (i = 0; i < MAX_STREAMS; i++) {
0578         destroy_stream(dice, AMDTP_IN_STREAM, i);
0579         destroy_stream(dice, AMDTP_OUT_STREAM, i);
0580     }
0581 
0582     amdtp_domain_destroy(&dice->domain);
0583 }
0584 
0585 void snd_dice_stream_update_duplex(struct snd_dice *dice)
0586 {
0587     struct reg_params tx_params, rx_params;
0588 
0589     /*
0590      * On a bus reset, the DICE firmware disables streaming and then goes
0591      * off contemplating its own navel for hundreds of milliseconds before
0592      * it can react to any of our attempts to reenable streaming.  This
0593      * means that we lose synchronization anyway, so we force our streams
0594      * to stop so that the application can restart them in an orderly
0595      * manner.
0596      */
0597     dice->global_enabled = false;
0598 
0599     if (get_register_params(dice, &tx_params, &rx_params) == 0) {
0600         amdtp_domain_stop(&dice->domain);
0601 
0602         stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
0603         stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
0604     }
0605 }
0606 
0607 int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
0608 {
0609     unsigned int rate;
0610     enum snd_dice_rate_mode mode;
0611     __be32 reg[2];
0612     struct reg_params tx_params, rx_params;
0613     int i;
0614     int err;
0615 
0616     /* If extended protocol is available, detect detail spec. */
0617     err = snd_dice_detect_extension_formats(dice);
0618     if (err >= 0)
0619         return err;
0620 
0621     /*
0622      * Available stream format is restricted at current mode of sampling
0623      * clock.
0624      */
0625     err = snd_dice_transaction_get_rate(dice, &rate);
0626     if (err < 0)
0627         return err;
0628 
0629     err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
0630     if (err < 0)
0631         return err;
0632 
0633     /*
0634      * Just after owning the unit (GLOBAL_OWNER), the unit can return
0635      * invalid stream formats. Selecting clock parameters have an effect
0636      * for the unit to refine it.
0637      */
0638     err = select_clock(dice, rate);
0639     if (err < 0)
0640         return err;
0641 
0642     err = get_register_params(dice, &tx_params, &rx_params);
0643     if (err < 0)
0644         return err;
0645 
0646     for (i = 0; i < tx_params.count; ++i) {
0647         err = snd_dice_transaction_read_tx(dice,
0648                 tx_params.size * i + TX_NUMBER_AUDIO,
0649                 reg, sizeof(reg));
0650         if (err < 0)
0651             return err;
0652         dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
0653         dice->tx_midi_ports[i] = max_t(unsigned int,
0654                 be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
0655     }
0656     for (i = 0; i < rx_params.count; ++i) {
0657         err = snd_dice_transaction_read_rx(dice,
0658                 rx_params.size * i + RX_NUMBER_AUDIO,
0659                 reg, sizeof(reg));
0660         if (err < 0)
0661             return err;
0662         dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
0663         dice->rx_midi_ports[i] = max_t(unsigned int,
0664                 be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
0665     }
0666 
0667     return 0;
0668 }
0669 
0670 static void dice_lock_changed(struct snd_dice *dice)
0671 {
0672     dice->dev_lock_changed = true;
0673     wake_up(&dice->hwdep_wait);
0674 }
0675 
0676 int snd_dice_stream_lock_try(struct snd_dice *dice)
0677 {
0678     int err;
0679 
0680     spin_lock_irq(&dice->lock);
0681 
0682     if (dice->dev_lock_count < 0) {
0683         err = -EBUSY;
0684         goto out;
0685     }
0686 
0687     if (dice->dev_lock_count++ == 0)
0688         dice_lock_changed(dice);
0689     err = 0;
0690 out:
0691     spin_unlock_irq(&dice->lock);
0692     return err;
0693 }
0694 
0695 void snd_dice_stream_lock_release(struct snd_dice *dice)
0696 {
0697     spin_lock_irq(&dice->lock);
0698 
0699     if (WARN_ON(dice->dev_lock_count <= 0))
0700         goto out;
0701 
0702     if (--dice->dev_lock_count == 0)
0703         dice_lock_changed(dice);
0704 out:
0705     spin_unlock_irq(&dice->lock);
0706 }