439 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * motu-stream.c - a part of driver for MOTU FireWire series4 *5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>6 */7 8#include "motu.h"9 10#define READY_TIMEOUT_MS 20011 12#define ISOC_COMM_CONTROL_OFFSET 0x0b0013#define ISOC_COMM_CONTROL_MASK 0xffff000014#define CHANGE_RX_ISOC_COMM_STATE 0x8000000015#define RX_ISOC_COMM_IS_ACTIVATED 0x4000000016#define RX_ISOC_COMM_CHANNEL_MASK 0x3f00000017#define RX_ISOC_COMM_CHANNEL_SHIFT 2418#define CHANGE_TX_ISOC_COMM_STATE 0x0080000019#define TX_ISOC_COMM_IS_ACTIVATED 0x0040000020#define TX_ISOC_COMM_CHANNEL_MASK 0x003f000021#define TX_ISOC_COMM_CHANNEL_SHIFT 1622 23#define PACKET_FORMAT_OFFSET 0x0b1024#define TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x0000008025#define RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x0000004026#define TX_PACKET_TRANSMISSION_SPEED_MASK 0x0000000f27 28static 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 62static 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, ®,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, ®,82 sizeof(reg));83}84 85static 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, ®,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, ®,106 sizeof(reg));107}108 109int 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 136int 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 201static 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, ®,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, ®,224 sizeof(reg));225}226 227int 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 data291 // blocks per packet, and the sequence of source packet header per data block as292 // 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 312stop_streams:313 amdtp_domain_stop(&motu->domain);314 finish_session(motu);315 return err;316}317 318void 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 332static 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 357static 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 else364 fw_iso_resources_destroy(&motu->rx_resources);365}366 367int 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 stopping391// streams.392void 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 402static void motu_lock_changed(struct snd_motu *motu)403{404 motu->dev_lock_changed = true;405 wake_up(&motu->hwdep_wait);406}407 408int 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;422out:423 spin_unlock_irq(&motu->lock);424 return err;425}426 427void 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);436out:437 spin_unlock_irq(&motu->lock);438}439