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