1 /* 2 * motu-stream.c - a part of driver for MOTU FireWire series 3 * 4 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> 5 * 6 * Licensed under the terms of the GNU General Public License, version 2. 7 */ 8 9 #include "motu.h" 10 11 #define CALLBACK_TIMEOUT 200 12 13 #define ISOC_COMM_CONTROL_OFFSET 0x0b00 14 #define ISOC_COMM_CONTROL_MASK 0xffff0000 15 #define CHANGE_RX_ISOC_COMM_STATE 0x80000000 16 #define RX_ISOC_COMM_IS_ACTIVATED 0x40000000 17 #define RX_ISOC_COMM_CHANNEL_MASK 0x3f000000 18 #define RX_ISOC_COMM_CHANNEL_SHIFT 24 19 #define CHANGE_TX_ISOC_COMM_STATE 0x00800000 20 #define TX_ISOC_COMM_IS_ACTIVATED 0x00400000 21 #define TX_ISOC_COMM_CHANNEL_MASK 0x003f0000 22 #define TX_ISOC_COMM_CHANNEL_SHIFT 16 23 24 #define PACKET_FORMAT_OFFSET 0x0b10 25 #define TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000080 26 #define RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040 27 #define TX_PACKET_TRANSMISSION_SPEED_MASK 0x0000000f 28 29 static int start_both_streams(struct snd_motu *motu, unsigned int rate) 30 { 31 unsigned int midi_ports = 0; 32 __be32 reg; 33 u32 data; 34 int err; 35 36 if (motu->spec->flags & SND_MOTU_SPEC_HAS_MIDI) 37 midi_ports = 1; 38 39 /* Set packet formation to our packet streaming engine. */ 40 err = amdtp_motu_set_parameters(&motu->rx_stream, rate, midi_ports, 41 &motu->rx_packet_formats); 42 if (err < 0) 43 return err; 44 45 err = amdtp_motu_set_parameters(&motu->tx_stream, rate, midi_ports, 46 &motu->tx_packet_formats); 47 if (err < 0) 48 return err; 49 50 /* Get isochronous resources on the bus. */ 51 err = fw_iso_resources_allocate(&motu->rx_resources, 52 amdtp_stream_get_max_payload(&motu->rx_stream), 53 fw_parent_device(motu->unit)->max_speed); 54 if (err < 0) 55 return err; 56 57 err = fw_iso_resources_allocate(&motu->tx_resources, 58 amdtp_stream_get_max_payload(&motu->tx_stream), 59 fw_parent_device(motu->unit)->max_speed); 60 if (err < 0) 61 return err; 62 63 /* Configure the unit to start isochronous communication. */ 64 err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®, 65 sizeof(reg)); 66 if (err < 0) 67 return err; 68 data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK; 69 70 data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED | 71 (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) | 72 CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED | 73 (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT); 74 75 reg = cpu_to_be32(data); 76 return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, ®, 77 sizeof(reg)); 78 } 79 80 static void stop_both_streams(struct snd_motu *motu) 81 { 82 __be32 reg; 83 u32 data; 84 int err; 85 86 err = motu->spec->protocol->switch_fetching_mode(motu, false); 87 if (err < 0) 88 return; 89 90 err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®, 91 sizeof(reg)); 92 if (err < 0) 93 return; 94 data = be32_to_cpu(reg); 95 96 data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED); 97 data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE; 98 99 reg = cpu_to_be32(data); 100 snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, ®, 101 sizeof(reg)); 102 103 fw_iso_resources_free(&motu->tx_resources); 104 fw_iso_resources_free(&motu->rx_resources); 105 } 106 107 static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream) 108 { 109 struct fw_iso_resources *resources; 110 int err; 111 112 if (stream == &motu->rx_stream) 113 resources = &motu->rx_resources; 114 else 115 resources = &motu->tx_resources; 116 117 err = amdtp_stream_start(stream, resources->channel, 118 fw_parent_device(motu->unit)->max_speed); 119 if (err < 0) 120 return err; 121 122 if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { 123 amdtp_stream_stop(stream); 124 fw_iso_resources_free(resources); 125 return -ETIMEDOUT; 126 } 127 128 return 0; 129 } 130 131 static void stop_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream) 132 { 133 struct fw_iso_resources *resources; 134 135 if (stream == &motu->rx_stream) 136 resources = &motu->rx_resources; 137 else 138 resources = &motu->tx_resources; 139 140 amdtp_stream_stop(stream); 141 fw_iso_resources_free(resources); 142 } 143 144 static int ensure_packet_formats(struct snd_motu *motu) 145 { 146 __be32 reg; 147 u32 data; 148 int err; 149 150 err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, ®, 151 sizeof(reg)); 152 if (err < 0) 153 return err; 154 data = be32_to_cpu(reg); 155 156 data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS | 157 RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS| 158 TX_PACKET_TRANSMISSION_SPEED_MASK); 159 if (motu->tx_packet_formats.differed_part_pcm_chunks[0] == 0) 160 data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS; 161 if (motu->rx_packet_formats.differed_part_pcm_chunks[0] == 0) 162 data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS; 163 data |= fw_parent_device(motu->unit)->max_speed; 164 165 reg = cpu_to_be32(data); 166 return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, ®, 167 sizeof(reg)); 168 } 169 170 int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate) 171 { 172 const struct snd_motu_protocol *protocol = motu->spec->protocol; 173 unsigned int curr_rate; 174 int err = 0; 175 176 if (motu->capture_substreams == 0 && motu->playback_substreams == 0) 177 return 0; 178 179 /* Some packet queueing errors. */ 180 if (amdtp_streaming_error(&motu->rx_stream) || 181 amdtp_streaming_error(&motu->tx_stream)) { 182 amdtp_stream_stop(&motu->rx_stream); 183 amdtp_stream_stop(&motu->tx_stream); 184 stop_both_streams(motu); 185 } 186 187 err = protocol->cache_packet_formats(motu); 188 if (err < 0) 189 return err; 190 191 /* Stop stream if rate is different. */ 192 err = protocol->get_clock_rate(motu, &curr_rate); 193 if (err < 0) { 194 dev_err(&motu->unit->device, 195 "fail to get sampling rate: %d\n", err); 196 return err; 197 } 198 if (rate == 0) 199 rate = curr_rate; 200 if (rate != curr_rate) { 201 amdtp_stream_stop(&motu->rx_stream); 202 amdtp_stream_stop(&motu->tx_stream); 203 stop_both_streams(motu); 204 } 205 206 if (!amdtp_stream_running(&motu->rx_stream)) { 207 err = protocol->set_clock_rate(motu, rate); 208 if (err < 0) { 209 dev_err(&motu->unit->device, 210 "fail to set sampling rate: %d\n", err); 211 return err; 212 } 213 214 err = ensure_packet_formats(motu); 215 if (err < 0) 216 return err; 217 218 err = start_both_streams(motu, rate); 219 if (err < 0) { 220 dev_err(&motu->unit->device, 221 "fail to start isochronous comm: %d\n", err); 222 stop_both_streams(motu); 223 return err; 224 } 225 226 err = start_isoc_ctx(motu, &motu->rx_stream); 227 if (err < 0) { 228 dev_err(&motu->unit->device, 229 "fail to start IT context: %d\n", err); 230 stop_both_streams(motu); 231 return err; 232 } 233 234 err = protocol->switch_fetching_mode(motu, true); 235 if (err < 0) { 236 dev_err(&motu->unit->device, 237 "fail to enable frame fetching: %d\n", err); 238 stop_both_streams(motu); 239 return err; 240 } 241 } 242 243 if (!amdtp_stream_running(&motu->tx_stream) && 244 motu->capture_substreams > 0) { 245 err = start_isoc_ctx(motu, &motu->tx_stream); 246 if (err < 0) { 247 dev_err(&motu->unit->device, 248 "fail to start IR context: %d", err); 249 amdtp_stream_stop(&motu->rx_stream); 250 stop_both_streams(motu); 251 return err; 252 } 253 } 254 255 return 0; 256 } 257 258 void snd_motu_stream_stop_duplex(struct snd_motu *motu) 259 { 260 if (motu->capture_substreams == 0) { 261 if (amdtp_stream_running(&motu->tx_stream)) 262 stop_isoc_ctx(motu, &motu->tx_stream); 263 264 if (motu->playback_substreams == 0) { 265 if (amdtp_stream_running(&motu->rx_stream)) 266 stop_isoc_ctx(motu, &motu->rx_stream); 267 stop_both_streams(motu); 268 } 269 } 270 } 271 272 static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir) 273 { 274 int err; 275 struct amdtp_stream *stream; 276 struct fw_iso_resources *resources; 277 278 if (dir == AMDTP_IN_STREAM) { 279 stream = &motu->tx_stream; 280 resources = &motu->tx_resources; 281 } else { 282 stream = &motu->rx_stream; 283 resources = &motu->rx_resources; 284 } 285 286 err = fw_iso_resources_init(resources, motu->unit); 287 if (err < 0) 288 return err; 289 290 err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol); 291 if (err < 0) { 292 amdtp_stream_destroy(stream); 293 fw_iso_resources_destroy(resources); 294 } 295 296 return err; 297 } 298 299 static void destroy_stream(struct snd_motu *motu, 300 enum amdtp_stream_direction dir) 301 { 302 struct amdtp_stream *stream; 303 struct fw_iso_resources *resources; 304 305 if (dir == AMDTP_IN_STREAM) { 306 stream = &motu->tx_stream; 307 resources = &motu->tx_resources; 308 } else { 309 stream = &motu->rx_stream; 310 resources = &motu->rx_resources; 311 } 312 313 amdtp_stream_destroy(stream); 314 fw_iso_resources_free(resources); 315 } 316 317 int snd_motu_stream_init_duplex(struct snd_motu *motu) 318 { 319 int err; 320 321 err = init_stream(motu, AMDTP_IN_STREAM); 322 if (err < 0) 323 return err; 324 325 err = init_stream(motu, AMDTP_OUT_STREAM); 326 if (err < 0) 327 destroy_stream(motu, AMDTP_IN_STREAM); 328 329 return err; 330 } 331 332 /* 333 * This function should be called before starting streams or after stopping 334 * streams. 335 */ 336 void snd_motu_stream_destroy_duplex(struct snd_motu *motu) 337 { 338 destroy_stream(motu, AMDTP_IN_STREAM); 339 destroy_stream(motu, AMDTP_OUT_STREAM); 340 341 motu->playback_substreams = 0; 342 motu->capture_substreams = 0; 343 } 344 345 static void motu_lock_changed(struct snd_motu *motu) 346 { 347 motu->dev_lock_changed = true; 348 wake_up(&motu->hwdep_wait); 349 } 350 351 int snd_motu_stream_lock_try(struct snd_motu *motu) 352 { 353 int err; 354 355 spin_lock_irq(&motu->lock); 356 357 if (motu->dev_lock_count < 0) { 358 err = -EBUSY; 359 goto out; 360 } 361 362 if (motu->dev_lock_count++ == 0) 363 motu_lock_changed(motu); 364 err = 0; 365 out: 366 spin_unlock_irq(&motu->lock); 367 return err; 368 } 369 370 void snd_motu_stream_lock_release(struct snd_motu *motu) 371 { 372 spin_lock_irq(&motu->lock); 373 374 if (WARN_ON(motu->dev_lock_count <= 0)) 375 goto out; 376 377 if (--motu->dev_lock_count == 0) 378 motu_lock_changed(motu); 379 out: 380 spin_unlock_irq(&motu->lock); 381 } 382