1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * digi00x-stream.c - a part of driver for Digidesign Digi 002/003 family 4 * 5 * Copyright (c) 2014-2015 Takashi Sakamoto 6 */ 7 8 #include "digi00x.h" 9 10 #define READY_TIMEOUT_MS 200 11 12 const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = { 13 [SND_DG00X_RATE_44100] = 44100, 14 [SND_DG00X_RATE_48000] = 48000, 15 [SND_DG00X_RATE_88200] = 88200, 16 [SND_DG00X_RATE_96000] = 96000, 17 }; 18 19 /* Multi Bit Linear Audio data channels for each sampling transfer frequency. */ 20 const unsigned int 21 snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT] = { 22 /* Analog/ADAT/SPDIF */ 23 [SND_DG00X_RATE_44100] = (8 + 8 + 2), 24 [SND_DG00X_RATE_48000] = (8 + 8 + 2), 25 /* Analog/SPDIF */ 26 [SND_DG00X_RATE_88200] = (8 + 2), 27 [SND_DG00X_RATE_96000] = (8 + 2), 28 }; 29 30 int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x, unsigned int *rate) 31 { 32 u32 data; 33 __be32 reg; 34 int err; 35 36 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST, 37 DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE, 38 ®, sizeof(reg), 0); 39 if (err < 0) 40 return err; 41 42 data = be32_to_cpu(reg) & 0x0f; 43 if (data < ARRAY_SIZE(snd_dg00x_stream_rates)) 44 *rate = snd_dg00x_stream_rates[data]; 45 else 46 err = -EIO; 47 48 return err; 49 } 50 51 int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate) 52 { 53 __be32 reg; 54 unsigned int i; 55 56 for (i = 0; i < ARRAY_SIZE(snd_dg00x_stream_rates); i++) { 57 if (rate == snd_dg00x_stream_rates[i]) 58 break; 59 } 60 if (i == ARRAY_SIZE(snd_dg00x_stream_rates)) 61 return -EINVAL; 62 63 reg = cpu_to_be32(i); 64 return snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, 65 DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE, 66 ®, sizeof(reg), 0); 67 } 68 69 int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x, 70 enum snd_dg00x_clock *clock) 71 { 72 __be32 reg; 73 int err; 74 75 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST, 76 DG00X_ADDR_BASE + DG00X_OFFSET_CLOCK_SOURCE, 77 ®, sizeof(reg), 0); 78 if (err < 0) 79 return err; 80 81 *clock = be32_to_cpu(reg) & 0x0f; 82 if (*clock >= SND_DG00X_CLOCK_COUNT) 83 err = -EIO; 84 85 return err; 86 } 87 88 int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect) 89 { 90 __be32 reg; 91 int err; 92 93 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST, 94 DG00X_ADDR_BASE + DG00X_OFFSET_DETECT_EXTERNAL, 95 ®, sizeof(reg), 0); 96 if (err >= 0) 97 *detect = be32_to_cpu(reg) > 0; 98 99 return err; 100 } 101 102 int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x, 103 unsigned int *rate) 104 { 105 u32 data; 106 __be32 reg; 107 int err; 108 109 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST, 110 DG00X_ADDR_BASE + DG00X_OFFSET_EXTERNAL_RATE, 111 ®, sizeof(reg), 0); 112 if (err < 0) 113 return err; 114 115 data = be32_to_cpu(reg) & 0x0f; 116 if (data < ARRAY_SIZE(snd_dg00x_stream_rates)) 117 *rate = snd_dg00x_stream_rates[data]; 118 /* This means desync. */ 119 else 120 err = -EBUSY; 121 122 return err; 123 } 124 125 static void finish_session(struct snd_dg00x *dg00x) 126 { 127 __be32 data; 128 129 data = cpu_to_be32(0x00000003); 130 snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, 131 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET, 132 &data, sizeof(data), 0); 133 134 // Unregister isochronous channels for both direction. 135 data = 0; 136 snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, 137 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS, 138 &data, sizeof(data), 0); 139 140 // Just after finishing the session, the device may lost transmitting 141 // functionality for a short time. 142 msleep(50); 143 } 144 145 static int begin_session(struct snd_dg00x *dg00x) 146 { 147 __be32 data; 148 u32 curr; 149 int err; 150 151 // Register isochronous channels for both direction. 152 data = cpu_to_be32((dg00x->tx_resources.channel << 16) | 153 dg00x->rx_resources.channel); 154 err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, 155 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS, 156 &data, sizeof(data), 0); 157 if (err < 0) 158 return err; 159 160 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST, 161 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE, 162 &data, sizeof(data), 0); 163 if (err < 0) 164 return err; 165 curr = be32_to_cpu(data); 166 167 if (curr == 0) 168 curr = 2; 169 170 curr--; 171 while (curr > 0) { 172 data = cpu_to_be32(curr); 173 err = snd_fw_transaction(dg00x->unit, 174 TCODE_WRITE_QUADLET_REQUEST, 175 DG00X_ADDR_BASE + 176 DG00X_OFFSET_STREAMING_SET, 177 &data, sizeof(data), 0); 178 if (err < 0) 179 break; 180 181 msleep(20); 182 curr--; 183 } 184 185 return err; 186 } 187 188 static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream, 189 unsigned int rate) 190 { 191 struct fw_iso_resources *resources; 192 int i; 193 int err; 194 195 // Check sampling rate. 196 for (i = 0; i < SND_DG00X_RATE_COUNT; i++) { 197 if (snd_dg00x_stream_rates[i] == rate) 198 break; 199 } 200 if (i == SND_DG00X_RATE_COUNT) 201 return -EINVAL; 202 203 if (stream == &dg00x->tx_stream) 204 resources = &dg00x->tx_resources; 205 else 206 resources = &dg00x->rx_resources; 207 208 err = amdtp_dot_set_parameters(stream, rate, 209 snd_dg00x_stream_pcm_channels[i]); 210 if (err < 0) 211 return err; 212 213 return fw_iso_resources_allocate(resources, 214 amdtp_stream_get_max_payload(stream), 215 fw_parent_device(dg00x->unit)->max_speed); 216 } 217 218 static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s) 219 { 220 struct fw_iso_resources *resources; 221 enum amdtp_stream_direction dir; 222 int err; 223 224 if (s == &dg00x->tx_stream) { 225 resources = &dg00x->tx_resources; 226 dir = AMDTP_IN_STREAM; 227 } else { 228 resources = &dg00x->rx_resources; 229 dir = AMDTP_OUT_STREAM; 230 } 231 232 err = fw_iso_resources_init(resources, dg00x->unit); 233 if (err < 0) 234 return err; 235 236 err = amdtp_dot_init(s, dg00x->unit, dir); 237 if (err < 0) 238 fw_iso_resources_destroy(resources); 239 240 return err; 241 } 242 243 static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s) 244 { 245 amdtp_stream_destroy(s); 246 247 if (s == &dg00x->tx_stream) 248 fw_iso_resources_destroy(&dg00x->tx_resources); 249 else 250 fw_iso_resources_destroy(&dg00x->rx_resources); 251 } 252 253 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) 254 { 255 int err; 256 257 err = init_stream(dg00x, &dg00x->rx_stream); 258 if (err < 0) 259 return err; 260 261 err = init_stream(dg00x, &dg00x->tx_stream); 262 if (err < 0) { 263 destroy_stream(dg00x, &dg00x->rx_stream); 264 return err; 265 } 266 267 err = amdtp_domain_init(&dg00x->domain); 268 if (err < 0) { 269 destroy_stream(dg00x, &dg00x->rx_stream); 270 destroy_stream(dg00x, &dg00x->tx_stream); 271 } 272 273 return err; 274 } 275 276 /* 277 * This function should be called before starting streams or after stopping 278 * streams. 279 */ 280 void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) 281 { 282 amdtp_domain_destroy(&dg00x->domain); 283 284 destroy_stream(dg00x, &dg00x->rx_stream); 285 destroy_stream(dg00x, &dg00x->tx_stream); 286 } 287 288 int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, 289 unsigned int frames_per_period, 290 unsigned int frames_per_buffer) 291 { 292 unsigned int curr_rate; 293 int err; 294 295 err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate); 296 if (err < 0) 297 return err; 298 if (rate == 0) 299 rate = curr_rate; 300 301 if (dg00x->substreams_counter == 0 || curr_rate != rate) { 302 amdtp_domain_stop(&dg00x->domain); 303 304 finish_session(dg00x); 305 306 fw_iso_resources_free(&dg00x->tx_resources); 307 fw_iso_resources_free(&dg00x->rx_resources); 308 309 err = snd_dg00x_stream_set_local_rate(dg00x, rate); 310 if (err < 0) 311 return err; 312 313 err = keep_resources(dg00x, &dg00x->rx_stream, rate); 314 if (err < 0) 315 return err; 316 317 err = keep_resources(dg00x, &dg00x->tx_stream, rate); 318 if (err < 0) { 319 fw_iso_resources_free(&dg00x->rx_resources); 320 return err; 321 } 322 323 err = amdtp_domain_set_events_per_period(&dg00x->domain, 324 frames_per_period, frames_per_buffer); 325 if (err < 0) { 326 fw_iso_resources_free(&dg00x->rx_resources); 327 fw_iso_resources_free(&dg00x->tx_resources); 328 return err; 329 } 330 } 331 332 return 0; 333 } 334 335 int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) 336 { 337 unsigned int generation = dg00x->rx_resources.generation; 338 int err = 0; 339 340 if (dg00x->substreams_counter == 0) 341 return 0; 342 343 if (amdtp_streaming_error(&dg00x->tx_stream) || 344 amdtp_streaming_error(&dg00x->rx_stream)) { 345 amdtp_domain_stop(&dg00x->domain); 346 finish_session(dg00x); 347 } 348 349 if (generation != fw_parent_device(dg00x->unit)->card->generation) { 350 err = fw_iso_resources_update(&dg00x->tx_resources); 351 if (err < 0) 352 goto error; 353 354 err = fw_iso_resources_update(&dg00x->rx_resources); 355 if (err < 0) 356 goto error; 357 } 358 359 /* 360 * No packets are transmitted without receiving packets, reagardless of 361 * which source of clock is used. 362 */ 363 if (!amdtp_stream_running(&dg00x->rx_stream)) { 364 int spd = fw_parent_device(dg00x->unit)->max_speed; 365 366 err = begin_session(dg00x); 367 if (err < 0) 368 goto error; 369 370 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream, 371 dg00x->rx_resources.channel, spd); 372 if (err < 0) 373 goto error; 374 375 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream, 376 dg00x->tx_resources.channel, spd); 377 if (err < 0) 378 goto error; 379 380 // NOTE: The device doesn't start packet transmission till receiving any packet. 381 // It ignores presentation time expressed by the value of syt field of CIP header 382 // in received packets. The sequence of the number of data blocks per packet is 383 // important for media clock recovery. 384 err = amdtp_domain_start(&dg00x->domain, 0, true, true); 385 if (err < 0) 386 goto error; 387 388 if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) { 389 err = -ETIMEDOUT; 390 goto error; 391 } 392 } 393 394 return 0; 395 error: 396 amdtp_domain_stop(&dg00x->domain); 397 finish_session(dg00x); 398 399 return err; 400 } 401 402 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x) 403 { 404 if (dg00x->substreams_counter == 0) { 405 amdtp_domain_stop(&dg00x->domain); 406 finish_session(dg00x); 407 408 fw_iso_resources_free(&dg00x->tx_resources); 409 fw_iso_resources_free(&dg00x->rx_resources); 410 } 411 } 412 413 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x) 414 { 415 fw_iso_resources_update(&dg00x->tx_resources); 416 fw_iso_resources_update(&dg00x->rx_resources); 417 418 amdtp_stream_update(&dg00x->tx_stream); 419 amdtp_stream_update(&dg00x->rx_stream); 420 } 421 422 void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x) 423 { 424 dg00x->dev_lock_changed = true; 425 wake_up(&dg00x->hwdep_wait); 426 } 427 428 int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x) 429 { 430 int err; 431 432 spin_lock_irq(&dg00x->lock); 433 434 /* user land lock this */ 435 if (dg00x->dev_lock_count < 0) { 436 err = -EBUSY; 437 goto end; 438 } 439 440 /* this is the first time */ 441 if (dg00x->dev_lock_count++ == 0) 442 snd_dg00x_stream_lock_changed(dg00x); 443 err = 0; 444 end: 445 spin_unlock_irq(&dg00x->lock); 446 return err; 447 } 448 449 void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x) 450 { 451 spin_lock_irq(&dg00x->lock); 452 453 if (WARN_ON(dg00x->dev_lock_count <= 0)) 454 goto end; 455 if (--dg00x->dev_lock_count == 0) 456 snd_dg00x_stream_lock_changed(dg00x); 457 end: 458 spin_unlock_irq(&dg00x->lock); 459 } 460
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.