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