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