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
snd_dice_stream_get_rate_mode(struct snd_dice * dice,unsigned int rate,enum snd_dice_rate_mode * mode)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 */
ensure_phase_lock(struct snd_dice * dice,unsigned int rate)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 ®, 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 ®, 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
get_register_params(struct snd_dice * dice,struct reg_params * tx_params,struct reg_params * rx_params)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
release_resources(struct snd_dice * dice)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
stop_streams(struct snd_dice * dice,enum amdtp_stream_direction dir,struct reg_params * params)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 ®, sizeof(reg));
160 } else {
161 snd_dice_transaction_write_rx(dice,
162 params->size * i + RX_ISOCHRONOUS,
163 ®, sizeof(reg));
164 }
165 }
166 }
167
keep_resources(struct snd_dice * dice,struct amdtp_stream * stream,struct fw_iso_resources * resources,unsigned int rate,unsigned int pcm_chs,unsigned int midi_ports)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
keep_dual_resources(struct snd_dice * dice,unsigned int rate,enum amdtp_stream_direction dir,struct reg_params * params)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
finish_session(struct snd_dice * dice,struct reg_params * tx_params,struct reg_params * rx_params)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
snd_dice_stream_reserve_duplex(struct snd_dice * dice,unsigned int rate,unsigned int events_per_period,unsigned int events_per_buffer)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
start_streams(struct snd_dice * dice,enum amdtp_stream_direction dir,unsigned int rate,struct reg_params * params)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 ®, sizeof(reg));
364 } else {
365 err = snd_dice_transaction_write_rx(dice,
366 params->size * i + RX_ISOCHRONOUS,
367 ®, 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 ®, 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 */
snd_dice_stream_start_duplex(struct snd_dice * dice)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 */
snd_dice_stream_stop_duplex(struct snd_dice * dice)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
init_stream(struct snd_dice * dice,enum amdtp_stream_direction dir,unsigned int index)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 */
destroy_stream(struct snd_dice * dice,enum amdtp_stream_direction dir,unsigned int index)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
snd_dice_stream_init_duplex(struct snd_dice * dice)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
snd_dice_stream_destroy_duplex(struct snd_dice * dice)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
snd_dice_stream_update_duplex(struct snd_dice * dice)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
snd_dice_stream_detect_current_formats(struct snd_dice * dice)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
dice_lock_changed(struct snd_dice * dice)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
snd_dice_stream_lock_try(struct snd_dice * dice)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
snd_dice_stream_lock_release(struct snd_dice * dice)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 }
725