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