~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/firewire/dice/dice-stream.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 READY_TIMEOUT_MS        200
 12 #define NOTIFICATION_TIMEOUT_MS 100
 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 static int select_clock(struct snd_dice *dice, unsigned int rate)
 61 {
 62         __be32 reg, new;
 63         u32 data;
 64         int i;
 65         int err;
 66 
 67         err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
 68                                                &reg, sizeof(reg));
 69         if (err < 0)
 70                 return err;
 71 
 72         data = be32_to_cpu(reg);
 73 
 74         data &= ~CLOCK_RATE_MASK;
 75         for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
 76                 if (snd_dice_rates[i] == rate)
 77                         break;
 78         }
 79         if (i == ARRAY_SIZE(snd_dice_rates))
 80                 return -EINVAL;
 81         data |= i << CLOCK_RATE_SHIFT;
 82 
 83         if (completion_done(&dice->clock_accepted))
 84                 reinit_completion(&dice->clock_accepted);
 85 
 86         new = cpu_to_be32(data);
 87         err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
 88                                                 &new, sizeof(new));
 89         if (err < 0)
 90                 return err;
 91 
 92         if (wait_for_completion_timeout(&dice->clock_accepted,
 93                         msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
 94                 if (reg != new)
 95                         return -ETIMEDOUT;
 96         }
 97 
 98         return 0;
 99 }
100 
101 static int get_register_params(struct snd_dice *dice,
102                                struct reg_params *tx_params,
103                                struct reg_params *rx_params)
104 {
105         __be32 reg[2];
106         int err;
107 
108         err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
109         if (err < 0)
110                 return err;
111         tx_params->count =
112                         min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
113         tx_params->size = be32_to_cpu(reg[1]) * 4;
114 
115         err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
116         if (err < 0)
117                 return err;
118         rx_params->count =
119                         min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
120         rx_params->size = be32_to_cpu(reg[1]) * 4;
121 
122         return 0;
123 }
124 
125 static void release_resources(struct snd_dice *dice)
126 {
127         int i;
128 
129         for (i = 0; i < MAX_STREAMS; ++i) {
130                 fw_iso_resources_free(&dice->tx_resources[i]);
131                 fw_iso_resources_free(&dice->rx_resources[i]);
132         }
133 }
134 
135 static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
136                          struct reg_params *params)
137 {
138         __be32 reg;
139         unsigned int i;
140 
141         for (i = 0; i < params->count; i++) {
142                 reg = cpu_to_be32((u32)-1);
143                 if (dir == AMDTP_IN_STREAM) {
144                         snd_dice_transaction_write_tx(dice,
145                                         params->size * i + TX_ISOCHRONOUS,
146                                         &reg, sizeof(reg));
147                 } else {
148                         snd_dice_transaction_write_rx(dice,
149                                         params->size * i + RX_ISOCHRONOUS,
150                                         &reg, sizeof(reg));
151                 }
152         }
153 }
154 
155 static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
156                           struct fw_iso_resources *resources, unsigned int rate,
157                           unsigned int pcm_chs, unsigned int midi_ports)
158 {
159         bool double_pcm_frames;
160         unsigned int i;
161         int err;
162 
163         // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
164         // one data block of AMDTP packet. Thus sampling transfer frequency is
165         // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
166         // transferred on AMDTP packets at 96 kHz. Two successive samples of a
167         // channel are stored consecutively in the packet. This quirk is called
168         // as 'Dual Wire'.
169         // For this quirk, blocking mode is required and PCM buffer size should
170         // be aligned to SYT_INTERVAL.
171         double_pcm_frames = (rate > 96000 && !dice->disable_double_pcm_frames);
172         if (double_pcm_frames) {
173                 rate /= 2;
174                 pcm_chs *= 2;
175         }
176 
177         err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
178                                          double_pcm_frames);
179         if (err < 0)
180                 return err;
181 
182         if (double_pcm_frames) {
183                 pcm_chs /= 2;
184 
185                 for (i = 0; i < pcm_chs; i++) {
186                         amdtp_am824_set_pcm_position(stream, i, i * 2);
187                         amdtp_am824_set_pcm_position(stream, i + pcm_chs,
188                                                      i * 2 + 1);
189                 }
190         }
191 
192         return fw_iso_resources_allocate(resources,
193                                 amdtp_stream_get_max_payload(stream),
194                                 fw_parent_device(dice->unit)->max_speed);
195 }
196 
197 static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
198                                enum amdtp_stream_direction dir,
199                                struct reg_params *params)
200 {
201         enum snd_dice_rate_mode mode;
202         int i;
203         int err;
204 
205         err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
206         if (err < 0)
207                 return err;
208 
209         for (i = 0; i < params->count; ++i) {
210                 __be32 reg[2];
211                 struct amdtp_stream *stream;
212                 struct fw_iso_resources *resources;
213                 unsigned int pcm_cache;
214                 unsigned int pcm_chs;
215                 unsigned int midi_ports;
216 
217                 if (dir == AMDTP_IN_STREAM) {
218                         stream = &dice->tx_stream[i];
219                         resources = &dice->tx_resources[i];
220 
221                         pcm_cache = dice->tx_pcm_chs[i][mode];
222                         err = snd_dice_transaction_read_tx(dice,
223                                         params->size * i + TX_NUMBER_AUDIO,
224                                         reg, sizeof(reg));
225                 } else {
226                         stream = &dice->rx_stream[i];
227                         resources = &dice->rx_resources[i];
228 
229                         pcm_cache = dice->rx_pcm_chs[i][mode];
230                         err = snd_dice_transaction_read_rx(dice,
231                                         params->size * i + RX_NUMBER_AUDIO,
232                                         reg, sizeof(reg));
233                 }
234                 if (err < 0)
235                         return err;
236                 pcm_chs = be32_to_cpu(reg[0]);
237                 midi_ports = be32_to_cpu(reg[1]);
238 
239                 // These are important for developer of this driver.
240                 if (pcm_chs != pcm_cache) {
241                         dev_info(&dice->unit->device,
242                                  "cache mismatch: pcm: %u:%u, midi: %u\n",
243                                  pcm_chs, pcm_cache, midi_ports);
244                         return -EPROTO;
245                 }
246 
247                 err = keep_resources(dice, stream, resources, rate, pcm_chs,
248                                      midi_ports);
249                 if (err < 0)
250                         return err;
251         }
252 
253         return 0;
254 }
255 
256 static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
257                            struct reg_params *rx_params)
258 {
259         stop_streams(dice, AMDTP_IN_STREAM, tx_params);
260         stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
261 
262         snd_dice_transaction_clear_enable(dice);
263 }
264 
265 int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
266                                    unsigned int events_per_period,
267                                    unsigned int events_per_buffer)
268 {
269         unsigned int curr_rate;
270         int err;
271 
272         // Check sampling transmission frequency.
273         err = snd_dice_transaction_get_rate(dice, &curr_rate);
274         if (err < 0)
275                 return err;
276         if (rate == 0)
277                 rate = curr_rate;
278 
279         if (dice->substreams_counter == 0 || curr_rate != rate) {
280                 struct reg_params tx_params, rx_params;
281 
282                 amdtp_domain_stop(&dice->domain);
283 
284                 err = get_register_params(dice, &tx_params, &rx_params);
285                 if (err < 0)
286                         return err;
287                 finish_session(dice, &tx_params, &rx_params);
288 
289                 release_resources(dice);
290 
291                 // Just after owning the unit (GLOBAL_OWNER), the unit can
292                 // return invalid stream formats. Selecting clock parameters
293                 // have an effect for the unit to refine it.
294                 err = select_clock(dice, rate);
295                 if (err < 0)
296                         return err;
297 
298                 // After changing sampling transfer frequency, the value of
299                 // register can be changed.
300                 err = get_register_params(dice, &tx_params, &rx_params);
301                 if (err < 0)
302                         return err;
303 
304                 err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
305                                           &tx_params);
306                 if (err < 0)
307                         goto error;
308 
309                 err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
310                                           &rx_params);
311                 if (err < 0)
312                         goto error;
313 
314                 err = amdtp_domain_set_events_per_period(&dice->domain,
315                                         events_per_period, events_per_buffer);
316                 if (err < 0)
317                         goto error;
318         }
319 
320         return 0;
321 error:
322         release_resources(dice);
323         return err;
324 }
325 
326 static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
327                          unsigned int rate, struct reg_params *params)
328 {
329         unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
330         int i;
331         int err;
332 
333         for (i = 0; i < params->count; i++) {
334                 struct amdtp_stream *stream;
335                 struct fw_iso_resources *resources;
336                 __be32 reg;
337 
338                 if (dir == AMDTP_IN_STREAM) {
339                         stream = dice->tx_stream + i;
340                         resources = dice->tx_resources + i;
341                 } else {
342                         stream = dice->rx_stream + i;
343                         resources = dice->rx_resources + i;
344                 }
345 
346                 reg = cpu_to_be32(resources->channel);
347                 if (dir == AMDTP_IN_STREAM) {
348                         err = snd_dice_transaction_write_tx(dice,
349                                         params->size * i + TX_ISOCHRONOUS,
350                                         &reg, sizeof(reg));
351                 } else {
352                         err = snd_dice_transaction_write_rx(dice,
353                                         params->size * i + RX_ISOCHRONOUS,
354                                         &reg, sizeof(reg));
355                 }
356                 if (err < 0)
357                         return err;
358 
359                 if (dir == AMDTP_IN_STREAM) {
360                         reg = cpu_to_be32(max_speed);
361                         err = snd_dice_transaction_write_tx(dice,
362                                         params->size * i + TX_SPEED,
363                                         &reg, sizeof(reg));
364                         if (err < 0)
365                                 return err;
366                 }
367 
368                 err = amdtp_domain_add_stream(&dice->domain, stream,
369                                               resources->channel, max_speed);
370                 if (err < 0)
371                         return err;
372         }
373 
374         return 0;
375 }
376 
377 /*
378  * MEMO: After this function, there're two states of streams:
379  *  - None streams are running.
380  *  - All streams are running.
381  */
382 int snd_dice_stream_start_duplex(struct snd_dice *dice)
383 {
384         unsigned int generation = dice->rx_resources[0].generation;
385         struct reg_params tx_params, rx_params;
386         unsigned int i;
387         unsigned int rate;
388         enum snd_dice_rate_mode mode;
389         int err;
390 
391         if (dice->substreams_counter == 0)
392                 return -EIO;
393 
394         err = get_register_params(dice, &tx_params, &rx_params);
395         if (err < 0)
396                 return err;
397 
398         // Check error of packet streaming.
399         for (i = 0; i < MAX_STREAMS; ++i) {
400                 if (amdtp_streaming_error(&dice->tx_stream[i]) ||
401                     amdtp_streaming_error(&dice->rx_stream[i])) {
402                         amdtp_domain_stop(&dice->domain);
403                         finish_session(dice, &tx_params, &rx_params);
404                         break;
405                 }
406         }
407 
408         if (generation != fw_parent_device(dice->unit)->card->generation) {
409                 for (i = 0; i < MAX_STREAMS; ++i) {
410                         if (i < tx_params.count)
411                                 fw_iso_resources_update(dice->tx_resources + i);
412                         if (i < rx_params.count)
413                                 fw_iso_resources_update(dice->rx_resources + i);
414                 }
415         }
416 
417         // Check required streams are running or not.
418         err = snd_dice_transaction_get_rate(dice, &rate);
419         if (err < 0)
420                 return err;
421         err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
422         if (err < 0)
423                 return err;
424         for (i = 0; i < MAX_STREAMS; ++i) {
425                 if (dice->tx_pcm_chs[i][mode] > 0 &&
426                     !amdtp_stream_running(&dice->tx_stream[i]))
427                         break;
428                 if (dice->rx_pcm_chs[i][mode] > 0 &&
429                     !amdtp_stream_running(&dice->rx_stream[i]))
430                         break;
431         }
432         if (i < MAX_STREAMS) {
433                 // Start both streams.
434                 err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
435                 if (err < 0)
436                         goto error;
437 
438                 err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
439                 if (err < 0)
440                         goto error;
441 
442                 err = snd_dice_transaction_set_enable(dice);
443                 if (err < 0) {
444                         dev_err(&dice->unit->device,
445                                 "fail to enable interface\n");
446                         goto error;
447                 }
448 
449                 // MEMO: The device immediately starts packet transmission when enabled. Some
450                 // devices are strictly to generate any discontinuity in the sequence of tx packet
451                 // when they receives invalid sequence of presentation time in CIP header. The
452                 // sequence replay for media clock recovery can suppress the behaviour.
453                 err = amdtp_domain_start(&dice->domain, 0, true, false);
454                 if (err < 0)
455                         goto error;
456 
457                 if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) {
458                         err = -ETIMEDOUT;
459                         goto error;
460                 }
461         }
462 
463         return 0;
464 error:
465         amdtp_domain_stop(&dice->domain);
466         finish_session(dice, &tx_params, &rx_params);
467         return err;
468 }
469 
470 /*
471  * MEMO: After this function, there're two states of streams:
472  *  - None streams are running.
473  *  - All streams are running.
474  */
475 void snd_dice_stream_stop_duplex(struct snd_dice *dice)
476 {
477         struct reg_params tx_params, rx_params;
478 
479         if (dice->substreams_counter == 0) {
480                 if (get_register_params(dice, &tx_params, &rx_params) >= 0)
481                         finish_session(dice, &tx_params, &rx_params);
482 
483                 amdtp_domain_stop(&dice->domain);
484                 release_resources(dice);
485         }
486 }
487 
488 static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
489                        unsigned int index)
490 {
491         struct amdtp_stream *stream;
492         struct fw_iso_resources *resources;
493         int err;
494 
495         if (dir == AMDTP_IN_STREAM) {
496                 stream = &dice->tx_stream[index];
497                 resources = &dice->tx_resources[index];
498         } else {
499                 stream = &dice->rx_stream[index];
500                 resources = &dice->rx_resources[index];
501         }
502 
503         err = fw_iso_resources_init(resources, dice->unit);
504         if (err < 0)
505                 goto end;
506         resources->channels_mask = 0x00000000ffffffffuLL;
507 
508         err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
509         if (err < 0) {
510                 amdtp_stream_destroy(stream);
511                 fw_iso_resources_destroy(resources);
512         }
513 end:
514         return err;
515 }
516 
517 /*
518  * This function should be called before starting streams or after stopping
519  * streams.
520  */
521 static void destroy_stream(struct snd_dice *dice,
522                            enum amdtp_stream_direction dir,
523                            unsigned int index)
524 {
525         struct amdtp_stream *stream;
526         struct fw_iso_resources *resources;
527 
528         if (dir == AMDTP_IN_STREAM) {
529                 stream = &dice->tx_stream[index];
530                 resources = &dice->tx_resources[index];
531         } else {
532                 stream = &dice->rx_stream[index];
533                 resources = &dice->rx_resources[index];
534         }
535 
536         amdtp_stream_destroy(stream);
537         fw_iso_resources_destroy(resources);
538 }
539 
540 int snd_dice_stream_init_duplex(struct snd_dice *dice)
541 {
542         int i, err;
543 
544         for (i = 0; i < MAX_STREAMS; i++) {
545                 err = init_stream(dice, AMDTP_IN_STREAM, i);
546                 if (err < 0) {
547                         for (; i >= 0; i--)
548                                 destroy_stream(dice, AMDTP_IN_STREAM, i);
549                         goto end;
550                 }
551         }
552 
553         for (i = 0; i < MAX_STREAMS; i++) {
554                 err = init_stream(dice, AMDTP_OUT_STREAM, i);
555                 if (err < 0) {
556                         for (; i >= 0; i--)
557                                 destroy_stream(dice, AMDTP_OUT_STREAM, i);
558                         for (i = 0; i < MAX_STREAMS; i++)
559                                 destroy_stream(dice, AMDTP_IN_STREAM, i);
560                         goto end;
561                 }
562         }
563 
564         err = amdtp_domain_init(&dice->domain);
565         if (err < 0) {
566                 for (i = 0; i < MAX_STREAMS; ++i) {
567                         destroy_stream(dice, AMDTP_OUT_STREAM, i);
568                         destroy_stream(dice, AMDTP_IN_STREAM, i);
569                 }
570         }
571 end:
572         return err;
573 }
574 
575 void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
576 {
577         unsigned int i;
578 
579         for (i = 0; i < MAX_STREAMS; i++) {
580                 destroy_stream(dice, AMDTP_IN_STREAM, i);
581                 destroy_stream(dice, AMDTP_OUT_STREAM, i);
582         }
583 
584         amdtp_domain_destroy(&dice->domain);
585 }
586 
587 void snd_dice_stream_update_duplex(struct snd_dice *dice)
588 {
589         struct reg_params tx_params, rx_params;
590 
591         /*
592          * On a bus reset, the DICE firmware disables streaming and then goes
593          * off contemplating its own navel for hundreds of milliseconds before
594          * it can react to any of our attempts to reenable streaming.  This
595          * means that we lose synchronization anyway, so we force our streams
596          * to stop so that the application can restart them in an orderly
597          * manner.
598          */
599         dice->global_enabled = false;
600 
601         if (get_register_params(dice, &tx_params, &rx_params) == 0) {
602                 amdtp_domain_stop(&dice->domain);
603 
604                 stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
605                 stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
606         }
607 }
608 
609 int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
610 {
611         unsigned int rate;
612         enum snd_dice_rate_mode mode;
613         __be32 reg[2];
614         struct reg_params tx_params, rx_params;
615         int i;
616         int err;
617 
618         /* If extended protocol is available, detect detail spec. */
619         err = snd_dice_detect_extension_formats(dice);
620         if (err >= 0)
621                 return err;
622 
623         /*
624          * Available stream format is restricted at current mode of sampling
625          * clock.
626          */
627         err = snd_dice_transaction_get_rate(dice, &rate);
628         if (err < 0)
629                 return err;
630 
631         err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
632         if (err < 0)
633                 return err;
634 
635         /*
636          * Just after owning the unit (GLOBAL_OWNER), the unit can return
637          * invalid stream formats. Selecting clock parameters have an effect
638          * for the unit to refine it.
639          */
640         err = select_clock(dice, rate);
641         if (err < 0)
642                 return err;
643 
644         err = get_register_params(dice, &tx_params, &rx_params);
645         if (err < 0)
646                 return err;
647 
648         for (i = 0; i < tx_params.count; ++i) {
649                 err = snd_dice_transaction_read_tx(dice,
650                                 tx_params.size * i + TX_NUMBER_AUDIO,
651                                 reg, sizeof(reg));
652                 if (err < 0)
653                         return err;
654                 dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
655                 dice->tx_midi_ports[i] = max_t(unsigned int,
656                                 be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
657         }
658         for (i = 0; i < rx_params.count; ++i) {
659                 err = snd_dice_transaction_read_rx(dice,
660                                 rx_params.size * i + RX_NUMBER_AUDIO,
661                                 reg, sizeof(reg));
662                 if (err < 0)
663                         return err;
664                 dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
665                 dice->rx_midi_ports[i] = max_t(unsigned int,
666                                 be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
667         }
668 
669         return 0;
670 }
671 
672 static void dice_lock_changed(struct snd_dice *dice)
673 {
674         dice->dev_lock_changed = true;
675         wake_up(&dice->hwdep_wait);
676 }
677 
678 int snd_dice_stream_lock_try(struct snd_dice *dice)
679 {
680         int err;
681 
682         spin_lock_irq(&dice->lock);
683 
684         if (dice->dev_lock_count < 0) {
685                 err = -EBUSY;
686                 goto out;
687         }
688 
689         if (dice->dev_lock_count++ == 0)
690                 dice_lock_changed(dice);
691         err = 0;
692 out:
693         spin_unlock_irq(&dice->lock);
694         return err;
695 }
696 
697 void snd_dice_stream_lock_release(struct snd_dice *dice)
698 {
699         spin_lock_irq(&dice->lock);
700 
701         if (WARN_ON(dice->dev_lock_count <= 0))
702                 goto out;
703 
704         if (--dice->dev_lock_count == 0)
705                 dice_lock_changed(dice);
706 out:
707         spin_unlock_irq(&dice->lock);
708 }
709 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php