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

TOMOYO Linux Cross Reference
Linux/sound/firewire/motu/motu-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  * motu-stream.c - a part of driver for MOTU FireWire series
  4  *
  5  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
  6  */
  7 
  8 #include "motu.h"
  9 
 10 #define READY_TIMEOUT_MS        200
 11 
 12 #define ISOC_COMM_CONTROL_OFFSET                0x0b00
 13 #define  ISOC_COMM_CONTROL_MASK                 0xffff0000
 14 #define  CHANGE_RX_ISOC_COMM_STATE              0x80000000
 15 #define  RX_ISOC_COMM_IS_ACTIVATED              0x40000000
 16 #define  RX_ISOC_COMM_CHANNEL_MASK              0x3f000000
 17 #define  RX_ISOC_COMM_CHANNEL_SHIFT             24
 18 #define  CHANGE_TX_ISOC_COMM_STATE              0x00800000
 19 #define  TX_ISOC_COMM_IS_ACTIVATED              0x00400000
 20 #define  TX_ISOC_COMM_CHANNEL_MASK              0x003f0000
 21 #define  TX_ISOC_COMM_CHANNEL_SHIFT             16
 22 
 23 #define PACKET_FORMAT_OFFSET                    0x0b10
 24 #define  TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000080
 25 #define  RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040
 26 #define  TX_PACKET_TRANSMISSION_SPEED_MASK      0x0000000f
 27 
 28 static int keep_resources(struct snd_motu *motu, unsigned int rate,
 29                           struct amdtp_stream *stream)
 30 {
 31         struct fw_iso_resources *resources;
 32         struct snd_motu_packet_format *packet_format;
 33         unsigned int midi_ports = 0;
 34         int err;
 35 
 36         if (stream == &motu->rx_stream) {
 37                 resources = &motu->rx_resources;
 38                 packet_format = &motu->rx_packet_formats;
 39 
 40                 if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
 41                     (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
 42                         midi_ports = 1;
 43         } else {
 44                 resources = &motu->tx_resources;
 45                 packet_format = &motu->tx_packet_formats;
 46 
 47                 if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
 48                     (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
 49                         midi_ports = 1;
 50         }
 51 
 52         err = amdtp_motu_set_parameters(stream, rate, midi_ports,
 53                                         packet_format);
 54         if (err < 0)
 55                 return err;
 56 
 57         return fw_iso_resources_allocate(resources,
 58                                 amdtp_stream_get_max_payload(stream),
 59                                 fw_parent_device(motu->unit)->max_speed);
 60 }
 61 
 62 static int begin_session(struct snd_motu *motu)
 63 {
 64         __be32 reg;
 65         u32 data;
 66         int err;
 67 
 68         // Configure the unit to start isochronous communication.
 69         err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
 70                                         sizeof(reg));
 71         if (err < 0)
 72                 return err;
 73         data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK;
 74 
 75         data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED |
 76                 (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) |
 77                 CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED |
 78                 (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT);
 79 
 80         reg = cpu_to_be32(data);
 81         return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
 82                                           sizeof(reg));
 83 }
 84 
 85 static void finish_session(struct snd_motu *motu)
 86 {
 87         __be32 reg;
 88         u32 data;
 89         int err;
 90 
 91         err = snd_motu_protocol_switch_fetching_mode(motu, false);
 92         if (err < 0)
 93                 return;
 94 
 95         err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
 96                                         sizeof(reg));
 97         if (err < 0)
 98                 return;
 99         data = be32_to_cpu(reg);
100 
101         data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED);
102         data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE;
103 
104         reg = cpu_to_be32(data);
105         snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
106                                    sizeof(reg));
107 }
108 
109 int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
110 {
111         int err;
112 
113         err = snd_motu_protocol_cache_packet_formats(motu);
114         if (err < 0)
115                 return err;
116 
117         if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) {
118                 motu->tx_packet_formats.midi_flag_offset = 4;
119                 motu->tx_packet_formats.midi_byte_offset = 6;
120         } else if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q) {
121                 motu->tx_packet_formats.midi_flag_offset = 8;
122                 motu->tx_packet_formats.midi_byte_offset = 7;
123         }
124 
125         if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) {
126                 motu->rx_packet_formats.midi_flag_offset = 4;
127                 motu->rx_packet_formats.midi_byte_offset = 6;
128         } else if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) {
129                 motu->rx_packet_formats.midi_flag_offset = 8;
130                 motu->rx_packet_formats.midi_byte_offset = 7;
131         }
132 
133         return 0;
134 }
135 
136 int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
137                                    unsigned int frames_per_period,
138                                    unsigned int frames_per_buffer)
139 {
140         unsigned int curr_rate;
141         int err;
142 
143         err = snd_motu_protocol_get_clock_rate(motu, &curr_rate);
144         if (err < 0)
145                 return err;
146         if (rate == 0)
147                 rate = curr_rate;
148 
149         if (motu->substreams_counter == 0 || curr_rate != rate) {
150                 amdtp_domain_stop(&motu->domain);
151                 finish_session(motu);
152 
153                 fw_iso_resources_free(&motu->tx_resources);
154                 fw_iso_resources_free(&motu->rx_resources);
155 
156                 kfree(motu->cache.event_offsets);
157                 motu->cache.event_offsets = NULL;
158 
159                 err = snd_motu_protocol_set_clock_rate(motu, rate);
160                 if (err < 0) {
161                         dev_err(&motu->unit->device,
162                                 "fail to set sampling rate: %d\n", err);
163                         return err;
164                 }
165 
166                 err = snd_motu_stream_cache_packet_formats(motu);
167                 if (err < 0)
168                         return err;
169 
170                 err = keep_resources(motu, rate, &motu->tx_stream);
171                 if (err < 0)
172                         return err;
173 
174                 err = keep_resources(motu, rate, &motu->rx_stream);
175                 if (err < 0) {
176                         fw_iso_resources_free(&motu->tx_resources);
177                         return err;
178                 }
179 
180                 err = amdtp_domain_set_events_per_period(&motu->domain,
181                                         frames_per_period, frames_per_buffer);
182                 if (err < 0) {
183                         fw_iso_resources_free(&motu->tx_resources);
184                         fw_iso_resources_free(&motu->rx_resources);
185                         return err;
186                 }
187 
188                 motu->cache.size = motu->tx_stream.syt_interval * frames_per_buffer;
189                 motu->cache.event_offsets = kcalloc(motu->cache.size, sizeof(*motu->cache.event_offsets),
190                                                   GFP_KERNEL);
191                 if (!motu->cache.event_offsets) {
192                         fw_iso_resources_free(&motu->tx_resources);
193                         fw_iso_resources_free(&motu->rx_resources);
194                         return -ENOMEM;
195                 }
196         }
197 
198         return 0;
199 }
200 
201 static int ensure_packet_formats(struct snd_motu *motu)
202 {
203         __be32 reg;
204         u32 data;
205         int err;
206 
207         err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, &reg,
208                                         sizeof(reg));
209         if (err < 0)
210                 return err;
211         data = be32_to_cpu(reg);
212 
213         data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS |
214                   RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS|
215                   TX_PACKET_TRANSMISSION_SPEED_MASK);
216         if (motu->spec->tx_fixed_pcm_chunks[0] == motu->tx_packet_formats.pcm_chunks[0])
217                 data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
218         if (motu->spec->rx_fixed_pcm_chunks[0] == motu->rx_packet_formats.pcm_chunks[0])
219                 data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
220         data |= fw_parent_device(motu->unit)->max_speed;
221 
222         reg = cpu_to_be32(data);
223         return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, &reg,
224                                           sizeof(reg));
225 }
226 
227 int snd_motu_stream_start_duplex(struct snd_motu *motu)
228 {
229         unsigned int generation = motu->rx_resources.generation;
230         int err = 0;
231 
232         if (motu->substreams_counter == 0)
233                 return 0;
234 
235         if (amdtp_streaming_error(&motu->rx_stream) ||
236             amdtp_streaming_error(&motu->tx_stream)) {
237                 amdtp_domain_stop(&motu->domain);
238                 finish_session(motu);
239         }
240 
241         if (generation != fw_parent_device(motu->unit)->card->generation) {
242                 err = fw_iso_resources_update(&motu->rx_resources);
243                 if (err < 0)
244                         return err;
245 
246                 err = fw_iso_resources_update(&motu->tx_resources);
247                 if (err < 0)
248                         return err;
249         }
250 
251         if (!amdtp_stream_running(&motu->rx_stream)) {
252                 int spd = fw_parent_device(motu->unit)->max_speed;
253 
254                 err = ensure_packet_formats(motu);
255                 if (err < 0)
256                         return err;
257 
258                 if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) {
259                         err = snd_motu_register_dsp_message_parser_init(motu);
260                         if (err < 0)
261                                 return err;
262                 } else if (motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP) {
263                         err = snd_motu_command_dsp_message_parser_init(motu, motu->tx_stream.sfc);
264                         if (err < 0)
265                                 return err;
266                 }
267 
268                 err = begin_session(motu);
269                 if (err < 0) {
270                         dev_err(&motu->unit->device,
271                                 "fail to start isochronous comm: %d\n", err);
272                         goto stop_streams;
273                 }
274 
275                 err = amdtp_domain_add_stream(&motu->domain, &motu->tx_stream,
276                                               motu->tx_resources.channel, spd);
277                 if (err < 0)
278                         goto stop_streams;
279 
280                 err = amdtp_domain_add_stream(&motu->domain, &motu->rx_stream,
281                                               motu->rx_resources.channel, spd);
282                 if (err < 0)
283                         goto stop_streams;
284 
285                 motu->cache.tail = 0;
286                 motu->cache.tx_cycle_count = UINT_MAX;
287                 motu->cache.head = 0;
288                 motu->cache.rx_cycle_count = UINT_MAX;
289 
290                 // NOTE: The device requires both of replay; the sequence of the number of data
291                 // blocks per packet, and the sequence of source packet header per data block as
292                 // presentation time.
293                 err = amdtp_domain_start(&motu->domain, 0, true, false);
294                 if (err < 0)
295                         goto stop_streams;
296 
297                 if (!amdtp_domain_wait_ready(&motu->domain, READY_TIMEOUT_MS)) {
298                         err = -ETIMEDOUT;
299                         goto stop_streams;
300                 }
301 
302                 err = snd_motu_protocol_switch_fetching_mode(motu, true);
303                 if (err < 0) {
304                         dev_err(&motu->unit->device,
305                                 "fail to enable frame fetching: %d\n", err);
306                         goto stop_streams;
307                 }
308         }
309 
310         return 0;
311 
312 stop_streams:
313         amdtp_domain_stop(&motu->domain);
314         finish_session(motu);
315         return err;
316 }
317 
318 void snd_motu_stream_stop_duplex(struct snd_motu *motu)
319 {
320         if (motu->substreams_counter == 0) {
321                 amdtp_domain_stop(&motu->domain);
322                 finish_session(motu);
323 
324                 fw_iso_resources_free(&motu->tx_resources);
325                 fw_iso_resources_free(&motu->rx_resources);
326 
327                 kfree(motu->cache.event_offsets);
328                 motu->cache.event_offsets = NULL;
329         }
330 }
331 
332 static int init_stream(struct snd_motu *motu, struct amdtp_stream *s)
333 {
334         struct fw_iso_resources *resources;
335         enum amdtp_stream_direction dir;
336         int err;
337 
338         if (s == &motu->tx_stream) {
339                 resources = &motu->tx_resources;
340                 dir = AMDTP_IN_STREAM;
341         } else {
342                 resources = &motu->rx_resources;
343                 dir = AMDTP_OUT_STREAM;
344         }
345 
346         err = fw_iso_resources_init(resources, motu->unit);
347         if (err < 0)
348                 return err;
349 
350         err = amdtp_motu_init(s, motu->unit, dir, motu->spec, &motu->cache);
351         if (err < 0)
352                 fw_iso_resources_destroy(resources);
353 
354         return err;
355 }
356 
357 static void destroy_stream(struct snd_motu *motu, struct amdtp_stream *s)
358 {
359         amdtp_stream_destroy(s);
360 
361         if (s == &motu->tx_stream)
362                 fw_iso_resources_destroy(&motu->tx_resources);
363         else
364                 fw_iso_resources_destroy(&motu->rx_resources);
365 }
366 
367 int snd_motu_stream_init_duplex(struct snd_motu *motu)
368 {
369         int err;
370 
371         err = init_stream(motu, &motu->tx_stream);
372         if (err < 0)
373                 return err;
374 
375         err = init_stream(motu, &motu->rx_stream);
376         if (err < 0) {
377                 destroy_stream(motu, &motu->tx_stream);
378                 return err;
379         }
380 
381         err = amdtp_domain_init(&motu->domain);
382         if (err < 0) {
383                 destroy_stream(motu, &motu->tx_stream);
384                 destroy_stream(motu, &motu->rx_stream);
385         }
386 
387         return err;
388 }
389 
390 // This function should be called before starting streams or after stopping
391 // streams.
392 void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
393 {
394         amdtp_domain_destroy(&motu->domain);
395 
396         destroy_stream(motu, &motu->rx_stream);
397         destroy_stream(motu, &motu->tx_stream);
398 
399         motu->substreams_counter = 0;
400 }
401 
402 static void motu_lock_changed(struct snd_motu *motu)
403 {
404         motu->dev_lock_changed = true;
405         wake_up(&motu->hwdep_wait);
406 }
407 
408 int snd_motu_stream_lock_try(struct snd_motu *motu)
409 {
410         int err;
411 
412         spin_lock_irq(&motu->lock);
413 
414         if (motu->dev_lock_count < 0) {
415                 err = -EBUSY;
416                 goto out;
417         }
418 
419         if (motu->dev_lock_count++ == 0)
420                 motu_lock_changed(motu);
421         err = 0;
422 out:
423         spin_unlock_irq(&motu->lock);
424         return err;
425 }
426 
427 void snd_motu_stream_lock_release(struct snd_motu *motu)
428 {
429         spin_lock_irq(&motu->lock);
430 
431         if (WARN_ON(motu->dev_lock_count <= 0))
432                 goto out;
433 
434         if (--motu->dev_lock_count == 0)
435                 motu_lock_changed(motu);
436 out:
437         spin_unlock_irq(&motu->lock);
438 }
439 

~ [ 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