| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * dice_stream.c - a part of driver for DICE based devices |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
|---|
| 5 | 6 | * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> |
|---|
| 6 | | - * |
|---|
| 7 | | - * Licensed under the terms of the GNU General Public License, version 2. |
|---|
| 8 | 7 | */ |
|---|
| 9 | 8 | |
|---|
| 10 | 9 | #include "dice.h" |
|---|
| .. | .. |
|---|
| 138 | 137 | |
|---|
| 139 | 138 | static void release_resources(struct snd_dice *dice) |
|---|
| 140 | 139 | { |
|---|
| 141 | | - unsigned int i; |
|---|
| 140 | + int i; |
|---|
| 142 | 141 | |
|---|
| 143 | | - for (i = 0; i < MAX_STREAMS; i++) { |
|---|
| 144 | | - if (amdtp_stream_running(&dice->tx_stream[i])) { |
|---|
| 145 | | - amdtp_stream_pcm_abort(&dice->tx_stream[i]); |
|---|
| 146 | | - amdtp_stream_stop(&dice->tx_stream[i]); |
|---|
| 147 | | - } |
|---|
| 148 | | - if (amdtp_stream_running(&dice->rx_stream[i])) { |
|---|
| 149 | | - amdtp_stream_pcm_abort(&dice->rx_stream[i]); |
|---|
| 150 | | - amdtp_stream_stop(&dice->rx_stream[i]); |
|---|
| 151 | | - } |
|---|
| 152 | | - |
|---|
| 142 | + for (i = 0; i < MAX_STREAMS; ++i) { |
|---|
| 153 | 143 | fw_iso_resources_free(&dice->tx_resources[i]); |
|---|
| 154 | 144 | fw_iso_resources_free(&dice->rx_resources[i]); |
|---|
| 155 | 145 | } |
|---|
| .. | .. |
|---|
| 175 | 165 | } |
|---|
| 176 | 166 | } |
|---|
| 177 | 167 | |
|---|
| 178 | | -static int keep_resources(struct snd_dice *dice, |
|---|
| 179 | | - enum amdtp_stream_direction dir, unsigned int index, |
|---|
| 180 | | - unsigned int rate, unsigned int pcm_chs, |
|---|
| 181 | | - unsigned int midi_ports) |
|---|
| 168 | +static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream, |
|---|
| 169 | + struct fw_iso_resources *resources, unsigned int rate, |
|---|
| 170 | + unsigned int pcm_chs, unsigned int midi_ports) |
|---|
| 182 | 171 | { |
|---|
| 183 | | - struct amdtp_stream *stream; |
|---|
| 184 | | - struct fw_iso_resources *resources; |
|---|
| 185 | 172 | bool double_pcm_frames; |
|---|
| 186 | 173 | unsigned int i; |
|---|
| 187 | 174 | int err; |
|---|
| 188 | 175 | |
|---|
| 189 | | - if (dir == AMDTP_IN_STREAM) { |
|---|
| 190 | | - stream = &dice->tx_stream[index]; |
|---|
| 191 | | - resources = &dice->tx_resources[index]; |
|---|
| 192 | | - } else { |
|---|
| 193 | | - stream = &dice->rx_stream[index]; |
|---|
| 194 | | - resources = &dice->rx_resources[index]; |
|---|
| 195 | | - } |
|---|
| 196 | | - |
|---|
| 197 | | - /* |
|---|
| 198 | | - * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in |
|---|
| 199 | | - * one data block of AMDTP packet. Thus sampling transfer frequency is |
|---|
| 200 | | - * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are |
|---|
| 201 | | - * transferred on AMDTP packets at 96 kHz. Two successive samples of a |
|---|
| 202 | | - * channel are stored consecutively in the packet. This quirk is called |
|---|
| 203 | | - * as 'Dual Wire'. |
|---|
| 204 | | - * For this quirk, blocking mode is required and PCM buffer size should |
|---|
| 205 | | - * be aligned to SYT_INTERVAL. |
|---|
| 206 | | - */ |
|---|
| 176 | + // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in |
|---|
| 177 | + // one data block of AMDTP packet. Thus sampling transfer frequency is |
|---|
| 178 | + // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are |
|---|
| 179 | + // transferred on AMDTP packets at 96 kHz. Two successive samples of a |
|---|
| 180 | + // channel are stored consecutively in the packet. This quirk is called |
|---|
| 181 | + // as 'Dual Wire'. |
|---|
| 182 | + // For this quirk, blocking mode is required and PCM buffer size should |
|---|
| 183 | + // be aligned to SYT_INTERVAL. |
|---|
| 207 | 184 | double_pcm_frames = rate > 96000; |
|---|
| 208 | 185 | if (double_pcm_frames) { |
|---|
| 209 | 186 | rate /= 2; |
|---|
| .. | .. |
|---|
| 230 | 207 | fw_parent_device(dice->unit)->max_speed); |
|---|
| 231 | 208 | } |
|---|
| 232 | 209 | |
|---|
| 233 | | -static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, |
|---|
| 234 | | - unsigned int rate, struct reg_params *params) |
|---|
| 210 | +static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, |
|---|
| 211 | + enum amdtp_stream_direction dir, |
|---|
| 212 | + struct reg_params *params) |
|---|
| 235 | 213 | { |
|---|
| 236 | | - __be32 reg[2]; |
|---|
| 237 | 214 | enum snd_dice_rate_mode mode; |
|---|
| 238 | | - unsigned int i, pcm_chs, midi_ports; |
|---|
| 239 | | - struct amdtp_stream *streams; |
|---|
| 240 | | - struct fw_iso_resources *resources; |
|---|
| 241 | | - struct fw_device *fw_dev = fw_parent_device(dice->unit); |
|---|
| 242 | | - int err = 0; |
|---|
| 243 | | - |
|---|
| 244 | | - if (dir == AMDTP_IN_STREAM) { |
|---|
| 245 | | - streams = dice->tx_stream; |
|---|
| 246 | | - resources = dice->tx_resources; |
|---|
| 247 | | - } else { |
|---|
| 248 | | - streams = dice->rx_stream; |
|---|
| 249 | | - resources = dice->rx_resources; |
|---|
| 250 | | - } |
|---|
| 215 | + int i; |
|---|
| 216 | + int err; |
|---|
| 251 | 217 | |
|---|
| 252 | 218 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); |
|---|
| 253 | 219 | if (err < 0) |
|---|
| 254 | 220 | return err; |
|---|
| 255 | 221 | |
|---|
| 256 | | - for (i = 0; i < params->count; i++) { |
|---|
| 222 | + for (i = 0; i < params->count; ++i) { |
|---|
| 223 | + __be32 reg[2]; |
|---|
| 224 | + struct amdtp_stream *stream; |
|---|
| 225 | + struct fw_iso_resources *resources; |
|---|
| 257 | 226 | unsigned int pcm_cache; |
|---|
| 258 | | - unsigned int midi_cache; |
|---|
| 227 | + unsigned int pcm_chs; |
|---|
| 228 | + unsigned int midi_ports; |
|---|
| 259 | 229 | |
|---|
| 260 | 230 | if (dir == AMDTP_IN_STREAM) { |
|---|
| 231 | + stream = &dice->tx_stream[i]; |
|---|
| 232 | + resources = &dice->tx_resources[i]; |
|---|
| 233 | + |
|---|
| 261 | 234 | pcm_cache = dice->tx_pcm_chs[i][mode]; |
|---|
| 262 | | - midi_cache = dice->tx_midi_ports[i]; |
|---|
| 263 | 235 | err = snd_dice_transaction_read_tx(dice, |
|---|
| 264 | 236 | params->size * i + TX_NUMBER_AUDIO, |
|---|
| 265 | 237 | reg, sizeof(reg)); |
|---|
| 266 | 238 | } else { |
|---|
| 239 | + stream = &dice->rx_stream[i]; |
|---|
| 240 | + resources = &dice->rx_resources[i]; |
|---|
| 241 | + |
|---|
| 267 | 242 | pcm_cache = dice->rx_pcm_chs[i][mode]; |
|---|
| 268 | | - midi_cache = dice->rx_midi_ports[i]; |
|---|
| 269 | 243 | err = snd_dice_transaction_read_rx(dice, |
|---|
| 270 | 244 | params->size * i + RX_NUMBER_AUDIO, |
|---|
| 271 | 245 | reg, sizeof(reg)); |
|---|
| .. | .. |
|---|
| 275 | 249 | pcm_chs = be32_to_cpu(reg[0]); |
|---|
| 276 | 250 | midi_ports = be32_to_cpu(reg[1]); |
|---|
| 277 | 251 | |
|---|
| 278 | | - /* These are important for developer of this driver. */ |
|---|
| 279 | | - if (pcm_chs != pcm_cache || midi_ports != midi_cache) { |
|---|
| 252 | + // These are important for developer of this driver. |
|---|
| 253 | + if (pcm_chs != pcm_cache) { |
|---|
| 280 | 254 | dev_info(&dice->unit->device, |
|---|
| 281 | | - "cache mismatch: pcm: %u:%u, midi: %u:%u\n", |
|---|
| 282 | | - pcm_chs, pcm_cache, midi_ports, midi_cache); |
|---|
| 255 | + "cache mismatch: pcm: %u:%u, midi: %u\n", |
|---|
| 256 | + pcm_chs, pcm_cache, midi_ports); |
|---|
| 283 | 257 | return -EPROTO; |
|---|
| 284 | 258 | } |
|---|
| 285 | 259 | |
|---|
| 286 | | - err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports); |
|---|
| 287 | | - if (err < 0) |
|---|
| 288 | | - return err; |
|---|
| 289 | | - |
|---|
| 290 | | - reg[0] = cpu_to_be32(resources[i].channel); |
|---|
| 291 | | - if (dir == AMDTP_IN_STREAM) { |
|---|
| 292 | | - err = snd_dice_transaction_write_tx(dice, |
|---|
| 293 | | - params->size * i + TX_ISOCHRONOUS, |
|---|
| 294 | | - reg, sizeof(reg[0])); |
|---|
| 295 | | - } else { |
|---|
| 296 | | - err = snd_dice_transaction_write_rx(dice, |
|---|
| 297 | | - params->size * i + RX_ISOCHRONOUS, |
|---|
| 298 | | - reg, sizeof(reg[0])); |
|---|
| 299 | | - } |
|---|
| 300 | | - if (err < 0) |
|---|
| 301 | | - return err; |
|---|
| 302 | | - |
|---|
| 303 | | - if (dir == AMDTP_IN_STREAM) { |
|---|
| 304 | | - reg[0] = cpu_to_be32(fw_dev->max_speed); |
|---|
| 305 | | - err = snd_dice_transaction_write_tx(dice, |
|---|
| 306 | | - params->size * i + TX_SPEED, |
|---|
| 307 | | - reg, sizeof(reg[0])); |
|---|
| 308 | | - if (err < 0) |
|---|
| 309 | | - return err; |
|---|
| 310 | | - } |
|---|
| 311 | | - |
|---|
| 312 | | - err = amdtp_stream_start(&streams[i], resources[i].channel, |
|---|
| 313 | | - fw_dev->max_speed); |
|---|
| 260 | + err = keep_resources(dice, stream, resources, rate, pcm_chs, |
|---|
| 261 | + midi_ports); |
|---|
| 314 | 262 | if (err < 0) |
|---|
| 315 | 263 | return err; |
|---|
| 316 | 264 | } |
|---|
| 317 | 265 | |
|---|
| 318 | | - return err; |
|---|
| 266 | + return 0; |
|---|
| 319 | 267 | } |
|---|
| 320 | 268 | |
|---|
| 321 | | -static int start_duplex_streams(struct snd_dice *dice, unsigned int rate) |
|---|
| 269 | +static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, |
|---|
| 270 | + struct reg_params *rx_params) |
|---|
| 322 | 271 | { |
|---|
| 323 | | - struct reg_params tx_params, rx_params; |
|---|
| 324 | | - int i; |
|---|
| 272 | + stop_streams(dice, AMDTP_IN_STREAM, tx_params); |
|---|
| 273 | + stop_streams(dice, AMDTP_OUT_STREAM, rx_params); |
|---|
| 274 | + |
|---|
| 275 | + snd_dice_transaction_clear_enable(dice); |
|---|
| 276 | +} |
|---|
| 277 | + |
|---|
| 278 | +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, |
|---|
| 279 | + unsigned int events_per_period, |
|---|
| 280 | + unsigned int events_per_buffer) |
|---|
| 281 | +{ |
|---|
| 282 | + unsigned int curr_rate; |
|---|
| 325 | 283 | int err; |
|---|
| 326 | 284 | |
|---|
| 327 | | - err = get_register_params(dice, &tx_params, &rx_params); |
|---|
| 285 | + // Check sampling transmission frequency. |
|---|
| 286 | + err = snd_dice_transaction_get_rate(dice, &curr_rate); |
|---|
| 328 | 287 | if (err < 0) |
|---|
| 329 | 288 | return err; |
|---|
| 289 | + if (rate == 0) |
|---|
| 290 | + rate = curr_rate; |
|---|
| 330 | 291 | |
|---|
| 331 | | - /* Stop transmission. */ |
|---|
| 332 | | - stop_streams(dice, AMDTP_IN_STREAM, &tx_params); |
|---|
| 333 | | - stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
|---|
| 334 | | - snd_dice_transaction_clear_enable(dice); |
|---|
| 335 | | - release_resources(dice); |
|---|
| 292 | + if (dice->substreams_counter == 0 || curr_rate != rate) { |
|---|
| 293 | + struct reg_params tx_params, rx_params; |
|---|
| 336 | 294 | |
|---|
| 337 | | - err = ensure_phase_lock(dice, rate); |
|---|
| 338 | | - if (err < 0) { |
|---|
| 339 | | - dev_err(&dice->unit->device, "fail to ensure phase lock\n"); |
|---|
| 340 | | - return err; |
|---|
| 341 | | - } |
|---|
| 295 | + amdtp_domain_stop(&dice->domain); |
|---|
| 342 | 296 | |
|---|
| 343 | | - /* Likely to have changed stream formats. */ |
|---|
| 344 | | - err = get_register_params(dice, &tx_params, &rx_params); |
|---|
| 345 | | - if (err < 0) |
|---|
| 346 | | - return err; |
|---|
| 297 | + err = get_register_params(dice, &tx_params, &rx_params); |
|---|
| 298 | + if (err < 0) |
|---|
| 299 | + return err; |
|---|
| 300 | + finish_session(dice, &tx_params, &rx_params); |
|---|
| 347 | 301 | |
|---|
| 348 | | - /* Start both streams. */ |
|---|
| 349 | | - err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); |
|---|
| 350 | | - if (err < 0) |
|---|
| 351 | | - goto error; |
|---|
| 352 | | - err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); |
|---|
| 353 | | - if (err < 0) |
|---|
| 354 | | - goto error; |
|---|
| 302 | + release_resources(dice); |
|---|
| 355 | 303 | |
|---|
| 356 | | - err = snd_dice_transaction_set_enable(dice); |
|---|
| 357 | | - if (err < 0) { |
|---|
| 358 | | - dev_err(&dice->unit->device, "fail to enable interface\n"); |
|---|
| 359 | | - goto error; |
|---|
| 360 | | - } |
|---|
| 304 | + // Just after owning the unit (GLOBAL_OWNER), the unit can |
|---|
| 305 | + // return invalid stream formats. Selecting clock parameters |
|---|
| 306 | + // have an effect for the unit to refine it. |
|---|
| 307 | + err = ensure_phase_lock(dice, rate); |
|---|
| 308 | + if (err < 0) |
|---|
| 309 | + return err; |
|---|
| 361 | 310 | |
|---|
| 362 | | - for (i = 0; i < MAX_STREAMS; i++) { |
|---|
| 363 | | - if ((i < tx_params.count && |
|---|
| 364 | | - !amdtp_stream_wait_callback(&dice->tx_stream[i], |
|---|
| 365 | | - CALLBACK_TIMEOUT)) || |
|---|
| 366 | | - (i < rx_params.count && |
|---|
| 367 | | - !amdtp_stream_wait_callback(&dice->rx_stream[i], |
|---|
| 368 | | - CALLBACK_TIMEOUT))) { |
|---|
| 369 | | - err = -ETIMEDOUT; |
|---|
| 311 | + // After changing sampling transfer frequency, the value of |
|---|
| 312 | + // register can be changed. |
|---|
| 313 | + err = get_register_params(dice, &tx_params, &rx_params); |
|---|
| 314 | + if (err < 0) |
|---|
| 315 | + return err; |
|---|
| 316 | + |
|---|
| 317 | + err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM, |
|---|
| 318 | + &tx_params); |
|---|
| 319 | + if (err < 0) |
|---|
| 370 | 320 | goto error; |
|---|
| 371 | | - } |
|---|
| 321 | + |
|---|
| 322 | + err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM, |
|---|
| 323 | + &rx_params); |
|---|
| 324 | + if (err < 0) |
|---|
| 325 | + goto error; |
|---|
| 326 | + |
|---|
| 327 | + err = amdtp_domain_set_events_per_period(&dice->domain, |
|---|
| 328 | + events_per_period, events_per_buffer); |
|---|
| 329 | + if (err < 0) |
|---|
| 330 | + goto error; |
|---|
| 372 | 331 | } |
|---|
| 373 | 332 | |
|---|
| 374 | 333 | return 0; |
|---|
| 375 | 334 | error: |
|---|
| 376 | | - stop_streams(dice, AMDTP_IN_STREAM, &tx_params); |
|---|
| 377 | | - stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
|---|
| 378 | | - snd_dice_transaction_clear_enable(dice); |
|---|
| 379 | 335 | release_resources(dice); |
|---|
| 380 | 336 | return err; |
|---|
| 337 | +} |
|---|
| 338 | + |
|---|
| 339 | +static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, |
|---|
| 340 | + unsigned int rate, struct reg_params *params) |
|---|
| 341 | +{ |
|---|
| 342 | + unsigned int max_speed = fw_parent_device(dice->unit)->max_speed; |
|---|
| 343 | + int i; |
|---|
| 344 | + int err; |
|---|
| 345 | + |
|---|
| 346 | + for (i = 0; i < params->count; i++) { |
|---|
| 347 | + struct amdtp_stream *stream; |
|---|
| 348 | + struct fw_iso_resources *resources; |
|---|
| 349 | + __be32 reg; |
|---|
| 350 | + |
|---|
| 351 | + if (dir == AMDTP_IN_STREAM) { |
|---|
| 352 | + stream = dice->tx_stream + i; |
|---|
| 353 | + resources = dice->tx_resources + i; |
|---|
| 354 | + } else { |
|---|
| 355 | + stream = dice->rx_stream + i; |
|---|
| 356 | + resources = dice->rx_resources + i; |
|---|
| 357 | + } |
|---|
| 358 | + |
|---|
| 359 | + reg = cpu_to_be32(resources->channel); |
|---|
| 360 | + if (dir == AMDTP_IN_STREAM) { |
|---|
| 361 | + err = snd_dice_transaction_write_tx(dice, |
|---|
| 362 | + params->size * i + TX_ISOCHRONOUS, |
|---|
| 363 | + ®, sizeof(reg)); |
|---|
| 364 | + } else { |
|---|
| 365 | + err = snd_dice_transaction_write_rx(dice, |
|---|
| 366 | + params->size * i + RX_ISOCHRONOUS, |
|---|
| 367 | + ®, sizeof(reg)); |
|---|
| 368 | + } |
|---|
| 369 | + if (err < 0) |
|---|
| 370 | + return err; |
|---|
| 371 | + |
|---|
| 372 | + if (dir == AMDTP_IN_STREAM) { |
|---|
| 373 | + reg = cpu_to_be32(max_speed); |
|---|
| 374 | + err = snd_dice_transaction_write_tx(dice, |
|---|
| 375 | + params->size * i + TX_SPEED, |
|---|
| 376 | + ®, sizeof(reg)); |
|---|
| 377 | + if (err < 0) |
|---|
| 378 | + return err; |
|---|
| 379 | + } |
|---|
| 380 | + |
|---|
| 381 | + err = amdtp_domain_add_stream(&dice->domain, stream, |
|---|
| 382 | + resources->channel, max_speed); |
|---|
| 383 | + if (err < 0) |
|---|
| 384 | + return err; |
|---|
| 385 | + } |
|---|
| 386 | + |
|---|
| 387 | + return 0; |
|---|
| 381 | 388 | } |
|---|
| 382 | 389 | |
|---|
| 383 | 390 | /* |
|---|
| .. | .. |
|---|
| 385 | 392 | * - None streams are running. |
|---|
| 386 | 393 | * - All streams are running. |
|---|
| 387 | 394 | */ |
|---|
| 388 | | -int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) |
|---|
| 395 | +int snd_dice_stream_start_duplex(struct snd_dice *dice) |
|---|
| 389 | 396 | { |
|---|
| 390 | | - unsigned int curr_rate; |
|---|
| 397 | + unsigned int generation = dice->rx_resources[0].generation; |
|---|
| 398 | + struct reg_params tx_params, rx_params; |
|---|
| 391 | 399 | unsigned int i; |
|---|
| 400 | + unsigned int rate; |
|---|
| 392 | 401 | enum snd_dice_rate_mode mode; |
|---|
| 393 | 402 | int err; |
|---|
| 394 | 403 | |
|---|
| 395 | 404 | if (dice->substreams_counter == 0) |
|---|
| 396 | 405 | return -EIO; |
|---|
| 397 | 406 | |
|---|
| 398 | | - /* Check sampling transmission frequency. */ |
|---|
| 399 | | - err = snd_dice_transaction_get_rate(dice, &curr_rate); |
|---|
| 400 | | - if (err < 0) { |
|---|
| 401 | | - dev_err(&dice->unit->device, |
|---|
| 402 | | - "fail to get sampling rate\n"); |
|---|
| 407 | + err = get_register_params(dice, &tx_params, &rx_params); |
|---|
| 408 | + if (err < 0) |
|---|
| 403 | 409 | return err; |
|---|
| 404 | | - } |
|---|
| 405 | | - if (rate == 0) |
|---|
| 406 | | - rate = curr_rate; |
|---|
| 407 | | - if (rate != curr_rate) |
|---|
| 408 | | - goto restart; |
|---|
| 409 | 410 | |
|---|
| 410 | | - /* Check error of packet streaming. */ |
|---|
| 411 | + // Check error of packet streaming. |
|---|
| 411 | 412 | for (i = 0; i < MAX_STREAMS; ++i) { |
|---|
| 412 | | - if (amdtp_streaming_error(&dice->tx_stream[i])) |
|---|
| 413 | + if (amdtp_streaming_error(&dice->tx_stream[i]) || |
|---|
| 414 | + amdtp_streaming_error(&dice->rx_stream[i])) { |
|---|
| 415 | + amdtp_domain_stop(&dice->domain); |
|---|
| 416 | + finish_session(dice, &tx_params, &rx_params); |
|---|
| 413 | 417 | break; |
|---|
| 414 | | - if (amdtp_streaming_error(&dice->rx_stream[i])) |
|---|
| 415 | | - break; |
|---|
| 418 | + } |
|---|
| 416 | 419 | } |
|---|
| 417 | | - if (i < MAX_STREAMS) |
|---|
| 418 | | - goto restart; |
|---|
| 419 | 420 | |
|---|
| 420 | | - /* Check required streams are running or not. */ |
|---|
| 421 | + if (generation != fw_parent_device(dice->unit)->card->generation) { |
|---|
| 422 | + for (i = 0; i < MAX_STREAMS; ++i) { |
|---|
| 423 | + if (i < tx_params.count) |
|---|
| 424 | + fw_iso_resources_update(dice->tx_resources + i); |
|---|
| 425 | + if (i < rx_params.count) |
|---|
| 426 | + fw_iso_resources_update(dice->rx_resources + i); |
|---|
| 427 | + } |
|---|
| 428 | + } |
|---|
| 429 | + |
|---|
| 430 | + // Check required streams are running or not. |
|---|
| 431 | + err = snd_dice_transaction_get_rate(dice, &rate); |
|---|
| 432 | + if (err < 0) |
|---|
| 433 | + return err; |
|---|
| 421 | 434 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); |
|---|
| 422 | 435 | if (err < 0) |
|---|
| 423 | 436 | return err; |
|---|
| .. | .. |
|---|
| 429 | 442 | !amdtp_stream_running(&dice->rx_stream[i])) |
|---|
| 430 | 443 | break; |
|---|
| 431 | 444 | } |
|---|
| 432 | | - if (i < MAX_STREAMS) |
|---|
| 433 | | - goto restart; |
|---|
| 445 | + if (i < MAX_STREAMS) { |
|---|
| 446 | + // Start both streams. |
|---|
| 447 | + err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); |
|---|
| 448 | + if (err < 0) |
|---|
| 449 | + goto error; |
|---|
| 450 | + |
|---|
| 451 | + err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); |
|---|
| 452 | + if (err < 0) |
|---|
| 453 | + goto error; |
|---|
| 454 | + |
|---|
| 455 | + err = snd_dice_transaction_set_enable(dice); |
|---|
| 456 | + if (err < 0) { |
|---|
| 457 | + dev_err(&dice->unit->device, |
|---|
| 458 | + "fail to enable interface\n"); |
|---|
| 459 | + goto error; |
|---|
| 460 | + } |
|---|
| 461 | + |
|---|
| 462 | + err = amdtp_domain_start(&dice->domain, 0); |
|---|
| 463 | + if (err < 0) |
|---|
| 464 | + goto error; |
|---|
| 465 | + |
|---|
| 466 | + for (i = 0; i < MAX_STREAMS; i++) { |
|---|
| 467 | + if ((i < tx_params.count && |
|---|
| 468 | + !amdtp_stream_wait_callback(&dice->tx_stream[i], |
|---|
| 469 | + CALLBACK_TIMEOUT)) || |
|---|
| 470 | + (i < rx_params.count && |
|---|
| 471 | + !amdtp_stream_wait_callback(&dice->rx_stream[i], |
|---|
| 472 | + CALLBACK_TIMEOUT))) { |
|---|
| 473 | + err = -ETIMEDOUT; |
|---|
| 474 | + goto error; |
|---|
| 475 | + } |
|---|
| 476 | + } |
|---|
| 477 | + } |
|---|
| 434 | 478 | |
|---|
| 435 | 479 | return 0; |
|---|
| 436 | | -restart: |
|---|
| 437 | | - return start_duplex_streams(dice, rate); |
|---|
| 480 | +error: |
|---|
| 481 | + amdtp_domain_stop(&dice->domain); |
|---|
| 482 | + finish_session(dice, &tx_params, &rx_params); |
|---|
| 483 | + return err; |
|---|
| 438 | 484 | } |
|---|
| 439 | 485 | |
|---|
| 440 | 486 | /* |
|---|
| .. | .. |
|---|
| 446 | 492 | { |
|---|
| 447 | 493 | struct reg_params tx_params, rx_params; |
|---|
| 448 | 494 | |
|---|
| 449 | | - if (dice->substreams_counter > 0) |
|---|
| 450 | | - return; |
|---|
| 495 | + if (dice->substreams_counter == 0) { |
|---|
| 496 | + if (get_register_params(dice, &tx_params, &rx_params) >= 0) |
|---|
| 497 | + finish_session(dice, &tx_params, &rx_params); |
|---|
| 451 | 498 | |
|---|
| 452 | | - snd_dice_transaction_clear_enable(dice); |
|---|
| 453 | | - |
|---|
| 454 | | - if (get_register_params(dice, &tx_params, &rx_params) == 0) { |
|---|
| 455 | | - stop_streams(dice, AMDTP_IN_STREAM, &tx_params); |
|---|
| 456 | | - stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
|---|
| 499 | + amdtp_domain_stop(&dice->domain); |
|---|
| 500 | + release_resources(dice); |
|---|
| 457 | 501 | } |
|---|
| 458 | | - |
|---|
| 459 | | - release_resources(dice); |
|---|
| 460 | 502 | } |
|---|
| 461 | 503 | |
|---|
| 462 | 504 | static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir, |
|---|
| .. | .. |
|---|
| 531 | 573 | destroy_stream(dice, AMDTP_OUT_STREAM, i); |
|---|
| 532 | 574 | for (i = 0; i < MAX_STREAMS; i++) |
|---|
| 533 | 575 | destroy_stream(dice, AMDTP_IN_STREAM, i); |
|---|
| 534 | | - break; |
|---|
| 576 | + goto end; |
|---|
| 577 | + } |
|---|
| 578 | + } |
|---|
| 579 | + |
|---|
| 580 | + err = amdtp_domain_init(&dice->domain); |
|---|
| 581 | + if (err < 0) { |
|---|
| 582 | + for (i = 0; i < MAX_STREAMS; ++i) { |
|---|
| 583 | + destroy_stream(dice, AMDTP_OUT_STREAM, i); |
|---|
| 584 | + destroy_stream(dice, AMDTP_IN_STREAM, i); |
|---|
| 535 | 585 | } |
|---|
| 536 | 586 | } |
|---|
| 537 | 587 | end: |
|---|
| .. | .. |
|---|
| 546 | 596 | destroy_stream(dice, AMDTP_IN_STREAM, i); |
|---|
| 547 | 597 | destroy_stream(dice, AMDTP_OUT_STREAM, i); |
|---|
| 548 | 598 | } |
|---|
| 599 | + |
|---|
| 600 | + amdtp_domain_destroy(&dice->domain); |
|---|
| 549 | 601 | } |
|---|
| 550 | 602 | |
|---|
| 551 | 603 | void snd_dice_stream_update_duplex(struct snd_dice *dice) |
|---|
| .. | .. |
|---|
| 563 | 615 | dice->global_enabled = false; |
|---|
| 564 | 616 | |
|---|
| 565 | 617 | if (get_register_params(dice, &tx_params, &rx_params) == 0) { |
|---|
| 618 | + amdtp_domain_stop(&dice->domain); |
|---|
| 619 | + |
|---|
| 566 | 620 | stop_streams(dice, AMDTP_IN_STREAM, &tx_params); |
|---|
| 567 | 621 | stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
|---|
| 568 | 622 | } |
|---|