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

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

Version: ~ [ linux-5.6-rc3 ] ~ [ linux-5.5.6 ] ~ [ linux-5.4.22 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.106 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.171 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.214 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.214 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * dice_stream.c - a part of driver for DICE based devices
  3  *
  4  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  5  * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
  6  *
  7  * Licensed under the terms of the GNU General Public License, version 2.
  8  */
  9 
 10 #include "dice.h"
 11 
 12 #define CALLBACK_TIMEOUT        200
 13 
 14 const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
 15         /* mode 0 */
 16         [0] =  32000,
 17         [1] =  44100,
 18         [2] =  48000,
 19         /* mode 1 */
 20         [3] =  88200,
 21         [4] =  96000,
 22         /* mode 2 */
 23         [5] = 176400,
 24         [6] = 192000,
 25 };
 26 
 27 int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
 28                                   unsigned int *mode)
 29 {
 30         int i;
 31 
 32         for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
 33                 if (!(dice->clock_caps & BIT(i)))
 34                         continue;
 35                 if (snd_dice_rates[i] != rate)
 36                         continue;
 37 
 38                 *mode = (i - 1) / 2;
 39                 return 0;
 40         }
 41         return -EINVAL;
 42 }
 43 
 44 static void release_resources(struct snd_dice *dice,
 45                               struct fw_iso_resources *resources)
 46 {
 47         unsigned int channel;
 48 
 49         /* Reset channel number */
 50         channel = cpu_to_be32((u32)-1);
 51         if (resources == &dice->tx_resources)
 52                 snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
 53                                               &channel, 4);
 54         else
 55                 snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
 56                                               &channel, 4);
 57 
 58         fw_iso_resources_free(resources);
 59 }
 60 
 61 static int keep_resources(struct snd_dice *dice,
 62                           struct fw_iso_resources *resources,
 63                           unsigned int max_payload_bytes)
 64 {
 65         unsigned int channel;
 66         int err;
 67 
 68         err = fw_iso_resources_allocate(resources, max_payload_bytes,
 69                                 fw_parent_device(dice->unit)->max_speed);
 70         if (err < 0)
 71                 goto end;
 72 
 73         /* Set channel number */
 74         channel = cpu_to_be32(resources->channel);
 75         if (resources == &dice->tx_resources)
 76                 err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
 77                                                     &channel, 4);
 78         else
 79                 err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
 80                                                     &channel, 4);
 81         if (err < 0)
 82                 release_resources(dice, resources);
 83 end:
 84         return err;
 85 }
 86 
 87 static void stop_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 88 {
 89         amdtp_stream_pcm_abort(stream);
 90         amdtp_stream_stop(stream);
 91 
 92         if (stream == &dice->tx_stream)
 93                 release_resources(dice, &dice->tx_resources);
 94         else
 95                 release_resources(dice, &dice->rx_resources);
 96 }
 97 
 98 static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
 99                         unsigned int rate)
100 {
101         struct fw_iso_resources *resources;
102         unsigned int i, mode, pcm_chs, midi_ports;
103         int err;
104 
105         err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
106         if (err < 0)
107                 goto end;
108         if (stream == &dice->tx_stream) {
109                 resources = &dice->tx_resources;
110                 pcm_chs = dice->tx_channels[mode];
111                 midi_ports = dice->tx_midi_ports[mode];
112         } else {
113                 resources = &dice->rx_resources;
114                 pcm_chs = dice->rx_channels[mode];
115                 midi_ports = dice->rx_midi_ports[mode];
116         }
117 
118         /*
119          * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
120          * one data block of AMDTP packet. Thus sampling transfer frequency is
121          * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
122          * transferred on AMDTP packets at 96 kHz. Two successive samples of a
123          * channel are stored consecutively in the packet. This quirk is called
124          * as 'Dual Wire'.
125          * For this quirk, blocking mode is required and PCM buffer size should
126          * be aligned to SYT_INTERVAL.
127          */
128         if (mode > 1) {
129                 rate /= 2;
130                 pcm_chs *= 2;
131                 stream->double_pcm_frames = true;
132         } else {
133                 stream->double_pcm_frames = false;
134         }
135 
136         amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports);
137         if (mode > 1) {
138                 pcm_chs /= 2;
139 
140                 for (i = 0; i < pcm_chs; i++) {
141                         stream->pcm_positions[i] = i * 2;
142                         stream->pcm_positions[i + pcm_chs] = i * 2 + 1;
143                 }
144         }
145 
146         err = keep_resources(dice, resources,
147                              amdtp_stream_get_max_payload(stream));
148         if (err < 0) {
149                 dev_err(&dice->unit->device,
150                         "fail to keep isochronous resources\n");
151                 goto end;
152         }
153 
154         err = amdtp_stream_start(stream, resources->channel,
155                                  fw_parent_device(dice->unit)->max_speed);
156         if (err < 0)
157                 release_resources(dice, resources);
158 end:
159         return err;
160 }
161 
162 static int get_sync_mode(struct snd_dice *dice, enum cip_flags *sync_mode)
163 {
164         u32 source;
165         int err;
166 
167         err = snd_dice_transaction_get_clock_source(dice, &source);
168         if (err < 0)
169                 goto end;
170 
171         switch (source) {
172         /* So-called 'SYT Match' modes, sync_to_syt value of packets received */
173         case CLOCK_SOURCE_ARX4: /* in 4th stream */
174         case CLOCK_SOURCE_ARX3: /* in 3rd stream */
175         case CLOCK_SOURCE_ARX2: /* in 2nd stream */
176                 err = -ENOSYS;
177                 break;
178         case CLOCK_SOURCE_ARX1: /* in 1st stream, which this driver uses */
179                 *sync_mode = 0;
180                 break;
181         default:
182                 *sync_mode = CIP_SYNC_TO_DEVICE;
183                 break;
184         }
185 end:
186         return err;
187 }
188 
189 int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
190 {
191         struct amdtp_stream *master, *slave;
192         unsigned int curr_rate;
193         enum cip_flags sync_mode;
194         int err = 0;
195 
196         if (dice->substreams_counter == 0)
197                 goto end;
198 
199         err = get_sync_mode(dice, &sync_mode);
200         if (err < 0)
201                 goto end;
202         if (sync_mode == CIP_SYNC_TO_DEVICE) {
203                 master = &dice->tx_stream;
204                 slave  = &dice->rx_stream;
205         } else {
206                 master = &dice->rx_stream;
207                 slave  = &dice->tx_stream;
208         }
209 
210         /* Some packet queueing errors. */
211         if (amdtp_streaming_error(master) || amdtp_streaming_error(slave))
212                 stop_stream(dice, master);
213 
214         /* Stop stream if rate is different. */
215         err = snd_dice_transaction_get_rate(dice, &curr_rate);
216         if (err < 0) {
217                 dev_err(&dice->unit->device,
218                         "fail to get sampling rate\n");
219                 goto end;
220         }
221         if (rate == 0)
222                 rate = curr_rate;
223         if (rate != curr_rate)
224                 stop_stream(dice, master);
225 
226         if (!amdtp_stream_running(master)) {
227                 stop_stream(dice, slave);
228                 snd_dice_transaction_clear_enable(dice);
229 
230                 amdtp_stream_set_sync(sync_mode, master, slave);
231 
232                 err = snd_dice_transaction_set_rate(dice, rate);
233                 if (err < 0) {
234                         dev_err(&dice->unit->device,
235                                 "fail to set sampling rate\n");
236                         goto end;
237                 }
238 
239                 /* Start both streams. */
240                 err = start_stream(dice, master, rate);
241                 if (err < 0) {
242                         dev_err(&dice->unit->device,
243                                 "fail to start AMDTP master stream\n");
244                         goto end;
245                 }
246                 err = start_stream(dice, slave, rate);
247                 if (err < 0) {
248                         dev_err(&dice->unit->device,
249                                 "fail to start AMDTP slave stream\n");
250                         stop_stream(dice, master);
251                         goto end;
252                 }
253                 err = snd_dice_transaction_set_enable(dice);
254                 if (err < 0) {
255                         dev_err(&dice->unit->device,
256                                 "fail to enable interface\n");
257                         stop_stream(dice, master);
258                         stop_stream(dice, slave);
259                         goto end;
260                 }
261 
262                 /* Wait first callbacks */
263                 if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT) ||
264                     !amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) {
265                         snd_dice_transaction_clear_enable(dice);
266                         stop_stream(dice, master);
267                         stop_stream(dice, slave);
268                         err = -ETIMEDOUT;
269                 }
270         }
271 end:
272         return err;
273 }
274 
275 void snd_dice_stream_stop_duplex(struct snd_dice *dice)
276 {
277         if (dice->substreams_counter > 0)
278                 return;
279 
280         snd_dice_transaction_clear_enable(dice);
281 
282         stop_stream(dice, &dice->tx_stream);
283         stop_stream(dice, &dice->rx_stream);
284 }
285 
286 static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
287 {
288         int err;
289         struct fw_iso_resources *resources;
290         enum amdtp_stream_direction dir;
291 
292         if (stream == &dice->tx_stream) {
293                 resources = &dice->tx_resources;
294                 dir = AMDTP_IN_STREAM;
295         } else {
296                 resources = &dice->rx_resources;
297                 dir = AMDTP_OUT_STREAM;
298         }
299 
300         err = fw_iso_resources_init(resources, dice->unit);
301         if (err < 0)
302                 goto end;
303         resources->channels_mask = 0x00000000ffffffffuLL;
304 
305         err = amdtp_stream_init(stream, dice->unit, dir, CIP_BLOCKING);
306         if (err < 0) {
307                 amdtp_stream_destroy(stream);
308                 fw_iso_resources_destroy(resources);
309         }
310 end:
311         return err;
312 }
313 
314 /*
315  * This function should be called before starting streams or after stopping
316  * streams.
317  */
318 static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
319 {
320         struct fw_iso_resources *resources;
321 
322         if (stream == &dice->tx_stream)
323                 resources = &dice->tx_resources;
324         else
325                 resources = &dice->rx_resources;
326 
327         amdtp_stream_destroy(stream);
328         fw_iso_resources_destroy(resources);
329 }
330 
331 int snd_dice_stream_init_duplex(struct snd_dice *dice)
332 {
333         int err;
334 
335         dice->substreams_counter = 0;
336 
337         err = init_stream(dice, &dice->tx_stream);
338         if (err < 0)
339                 goto end;
340 
341         err = init_stream(dice, &dice->rx_stream);
342         if (err < 0)
343                 destroy_stream(dice, &dice->tx_stream);
344 end:
345         return err;
346 }
347 
348 void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
349 {
350         snd_dice_transaction_clear_enable(dice);
351 
352         destroy_stream(dice, &dice->tx_stream);
353         destroy_stream(dice, &dice->rx_stream);
354 
355         dice->substreams_counter = 0;
356 }
357 
358 void snd_dice_stream_update_duplex(struct snd_dice *dice)
359 {
360         /*
361          * On a bus reset, the DICE firmware disables streaming and then goes
362          * off contemplating its own navel for hundreds of milliseconds before
363          * it can react to any of our attempts to reenable streaming.  This
364          * means that we lose synchronization anyway, so we force our streams
365          * to stop so that the application can restart them in an orderly
366          * manner.
367          */
368         dice->global_enabled = false;
369 
370         stop_stream(dice, &dice->rx_stream);
371         stop_stream(dice, &dice->tx_stream);
372 
373         fw_iso_resources_update(&dice->rx_resources);
374         fw_iso_resources_update(&dice->tx_resources);
375 }
376 
377 static void dice_lock_changed(struct snd_dice *dice)
378 {
379         dice->dev_lock_changed = true;
380         wake_up(&dice->hwdep_wait);
381 }
382 
383 int snd_dice_stream_lock_try(struct snd_dice *dice)
384 {
385         int err;
386 
387         spin_lock_irq(&dice->lock);
388 
389         if (dice->dev_lock_count < 0) {
390                 err = -EBUSY;
391                 goto out;
392         }
393 
394         if (dice->dev_lock_count++ == 0)
395                 dice_lock_changed(dice);
396         err = 0;
397 out:
398         spin_unlock_irq(&dice->lock);
399         return err;
400 }
401 
402 void snd_dice_stream_lock_release(struct snd_dice *dice)
403 {
404         spin_lock_irq(&dice->lock);
405 
406         if (WARN_ON(dice->dev_lock_count <= 0))
407                 goto out;
408 
409         if (--dice->dev_lock_count == 0)
410                 dice_lock_changed(dice);
411 out:
412         spin_unlock_irq(&dice->lock);
413 }
414 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp