Blame view
sound/firewire/dice/dice-stream.c
12.3 KB
6eb6c81ee ALSA: dice: Split... |
1 2 3 4 5 6 7 8 9 10 |
/* * dice_stream.c - a part of driver for DICE based devices * * Copyright (c) Clemens Ladisch <clemens@ladisch.de> * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> * * Licensed under the terms of the GNU General Public License, version 2. */ #include "dice.h" |
288a8d0cb ALSA: dice: Chang... |
11 |
#define CALLBACK_TIMEOUT 200 |
dfabc0eee ALSA: dice: ensur... |
12 |
#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC) |
288a8d0cb ALSA: dice: Chang... |
13 |
|
8cc1a8ab4 ALSA: dice: use s... |
14 15 16 17 |
struct reg_params { unsigned int count; unsigned int size; }; |
6eb6c81ee ALSA: dice: Split... |
18 19 20 21 22 23 24 25 26 27 28 29 |
const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { /* mode 0 */ [0] = 32000, [1] = 44100, [2] = 48000, /* mode 1 */ [3] = 88200, [4] = 96000, /* mode 2 */ [5] = 176400, [6] = 192000, }; |
dfabc0eee ALSA: dice: ensur... |
30 31 32 33 34 35 |
/* * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE * to GLOBAL_STATUS. Especially, just after powering on, these are different. */ static int ensure_phase_lock(struct snd_dice *dice) { |
fbeac84db ALSA: dice: old f... |
36 |
__be32 reg, nominal; |
dfabc0eee ALSA: dice: ensur... |
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
int err; err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT, ®, sizeof(reg)); if (err < 0) return err; if (completion_done(&dice->clock_accepted)) reinit_completion(&dice->clock_accepted); err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, ®, sizeof(reg)); if (err < 0) return err; if (wait_for_completion_timeout(&dice->clock_accepted, |
fbeac84db ALSA: dice: old f... |
53 54 55 56 57 58 59 60 61 62 63 64 65 |
msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { /* * Old versions of Dice firmware transfer no notification when * the same clock status as current one is set. In this case, * just check current clock status. */ err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS, &nominal, sizeof(nominal)); if (err < 0) return err; if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED)) return -ETIMEDOUT; } |
dfabc0eee ALSA: dice: ensur... |
66 67 68 |
return 0; } |
8cc1a8ab4 ALSA: dice: use s... |
69 70 71 |
static int get_register_params(struct snd_dice *dice, struct reg_params *tx_params, struct reg_params *rx_params) |
6eb6c81ee ALSA: dice: Split... |
72 |
{ |
436b5abe2 ALSA: dice: handl... |
73 |
__be32 reg[2]; |
6eb6c81ee ALSA: dice: Split... |
74 |
int err; |
436b5abe2 ALSA: dice: handl... |
75 |
err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg)); |
6eb6c81ee ALSA: dice: Split... |
76 |
if (err < 0) |
436b5abe2 ALSA: dice: handl... |
77 |
return err; |
8cc1a8ab4 ALSA: dice: use s... |
78 79 80 |
tx_params->count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); tx_params->size = be32_to_cpu(reg[1]) * 4; |
6eb6c81ee ALSA: dice: Split... |
81 |
|
436b5abe2 ALSA: dice: handl... |
82 |
err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg)); |
288a8d0cb ALSA: dice: Chang... |
83 |
if (err < 0) |
436b5abe2 ALSA: dice: handl... |
84 |
return err; |
8cc1a8ab4 ALSA: dice: use s... |
85 86 87 |
rx_params->count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); rx_params->size = be32_to_cpu(reg[1]) * 4; |
436b5abe2 ALSA: dice: handl... |
88 89 |
return 0; |
6eb6c81ee ALSA: dice: Split... |
90 |
} |
436b5abe2 ALSA: dice: handl... |
91 |
static void release_resources(struct snd_dice *dice) |
6eb6c81ee ALSA: dice: Split... |
92 |
{ |
436b5abe2 ALSA: dice: handl... |
93 94 95 96 97 98 99 100 101 102 103 |
unsigned int i; for (i = 0; i < MAX_STREAMS; i++) { if (amdtp_stream_running(&dice->tx_stream[i])) { amdtp_stream_pcm_abort(&dice->tx_stream[i]); amdtp_stream_stop(&dice->tx_stream[i]); } if (amdtp_stream_running(&dice->rx_stream[i])) { amdtp_stream_pcm_abort(&dice->rx_stream[i]); amdtp_stream_stop(&dice->rx_stream[i]); } |
c50fb91f5 ALSA: dice: Split... |
104 |
|
436b5abe2 ALSA: dice: handl... |
105 106 107 |
fw_iso_resources_free(&dice->tx_resources[i]); fw_iso_resources_free(&dice->rx_resources[i]); } |
6eb6c81ee ALSA: dice: Split... |
108 |
} |
436b5abe2 ALSA: dice: handl... |
109 |
static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, |
8cc1a8ab4 ALSA: dice: use s... |
110 |
struct reg_params *params) |
6eb6c81ee ALSA: dice: Split... |
111 |
{ |
436b5abe2 ALSA: dice: handl... |
112 113 |
__be32 reg; unsigned int i; |
8cc1a8ab4 ALSA: dice: use s... |
114 |
for (i = 0; i < params->count; i++) { |
436b5abe2 ALSA: dice: handl... |
115 116 117 |
reg = cpu_to_be32((u32)-1); if (dir == AMDTP_IN_STREAM) { snd_dice_transaction_write_tx(dice, |
8cc1a8ab4 ALSA: dice: use s... |
118 119 |
params->size * i + TX_ISOCHRONOUS, ®, sizeof(reg)); |
436b5abe2 ALSA: dice: handl... |
120 121 |
} else { snd_dice_transaction_write_rx(dice, |
8cc1a8ab4 ALSA: dice: use s... |
122 123 |
params->size * i + RX_ISOCHRONOUS, ®, sizeof(reg)); |
436b5abe2 ALSA: dice: handl... |
124 125 126 127 128 129 130 131 132 133 |
} } } static int keep_resources(struct snd_dice *dice, enum amdtp_stream_direction dir, unsigned int index, unsigned int rate, unsigned int pcm_chs, unsigned int midi_ports) { struct amdtp_stream *stream; |
9a02843ca ALSA: dice: Add s... |
134 |
struct fw_iso_resources *resources; |
27ec83b5c ALSA: firewire-li... |
135 |
bool double_pcm_frames; |
436b5abe2 ALSA: dice: handl... |
136 |
unsigned int i; |
288a8d0cb ALSA: dice: Chang... |
137 |
int err; |
6eb6c81ee ALSA: dice: Split... |
138 |
|
436b5abe2 ALSA: dice: handl... |
139 140 141 |
if (dir == AMDTP_IN_STREAM) { stream = &dice->tx_stream[index]; resources = &dice->tx_resources[index]; |
9a02843ca ALSA: dice: Add s... |
142 |
} else { |
436b5abe2 ALSA: dice: handl... |
143 144 |
stream = &dice->rx_stream[index]; resources = &dice->rx_resources[index]; |
9a02843ca ALSA: dice: Add s... |
145 |
} |
6eb6c81ee ALSA: dice: Split... |
146 |
|
288a8d0cb ALSA: dice: Chang... |
147 148 149 150 151 152 153 154 155 156 |
/* * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in * one data block of AMDTP packet. Thus sampling transfer frequency is * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are * transferred on AMDTP packets at 96 kHz. Two successive samples of a * channel are stored consecutively in the packet. This quirk is called * as 'Dual Wire'. * For this quirk, blocking mode is required and PCM buffer size should * be aligned to SYT_INTERVAL. */ |
6f688268b ALSA: dice: purge... |
157 |
double_pcm_frames = rate > 96000; |
27ec83b5c ALSA: firewire-li... |
158 |
if (double_pcm_frames) { |
288a8d0cb ALSA: dice: Chang... |
159 160 |
rate /= 2; pcm_chs *= 2; |
288a8d0cb ALSA: dice: Chang... |
161 |
} |
6eb6c81ee ALSA: dice: Split... |
162 |
|
51c29fd21 ALSA: firewire-li... |
163 164 |
err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports, double_pcm_frames); |
547e631ce ALSA: firewire-li... |
165 |
if (err < 0) |
436b5abe2 ALSA: dice: handl... |
166 |
return err; |
547e631ce ALSA: firewire-li... |
167 |
|
27ec83b5c ALSA: firewire-li... |
168 |
if (double_pcm_frames) { |
288a8d0cb ALSA: dice: Chang... |
169 |
pcm_chs /= 2; |
6eb6c81ee ALSA: dice: Split... |
170 |
|
288a8d0cb ALSA: dice: Chang... |
171 |
for (i = 0; i < pcm_chs; i++) { |
f65be911c ALSA: firewire-li... |
172 173 174 |
amdtp_am824_set_pcm_position(stream, i, i * 2); amdtp_am824_set_pcm_position(stream, i + pcm_chs, i * 2 + 1); |
288a8d0cb ALSA: dice: Chang... |
175 176 |
} } |
436b5abe2 ALSA: dice: handl... |
177 178 179 180 181 182 |
return fw_iso_resources_allocate(resources, amdtp_stream_get_max_payload(stream), fw_parent_device(dice->unit)->max_speed); } static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, |
8cc1a8ab4 ALSA: dice: use s... |
183 |
unsigned int rate, struct reg_params *params) |
436b5abe2 ALSA: dice: handl... |
184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
{ __be32 reg[2]; unsigned int i, pcm_chs, midi_ports; struct amdtp_stream *streams; struct fw_iso_resources *resources; int err = 0; if (dir == AMDTP_IN_STREAM) { streams = dice->tx_stream; resources = dice->tx_resources; } else { streams = dice->rx_stream; resources = dice->rx_resources; } |
8cc1a8ab4 ALSA: dice: use s... |
198 |
for (i = 0; i < params->count; i++) { |
436b5abe2 ALSA: dice: handl... |
199 200 |
if (dir == AMDTP_IN_STREAM) { err = snd_dice_transaction_read_tx(dice, |
8cc1a8ab4 ALSA: dice: use s... |
201 202 |
params->size * i + TX_NUMBER_AUDIO, reg, sizeof(reg)); |
436b5abe2 ALSA: dice: handl... |
203 204 |
} else { err = snd_dice_transaction_read_rx(dice, |
8cc1a8ab4 ALSA: dice: use s... |
205 206 |
params->size * i + RX_NUMBER_AUDIO, reg, sizeof(reg)); |
436b5abe2 ALSA: dice: handl... |
207 208 209 210 211 212 213 214 215 216 217 218 219 |
} if (err < 0) return err; pcm_chs = be32_to_cpu(reg[0]); midi_ports = be32_to_cpu(reg[1]); err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports); if (err < 0) return err; reg[0] = cpu_to_be32(resources[i].channel); if (dir == AMDTP_IN_STREAM) { err = snd_dice_transaction_write_tx(dice, |
8cc1a8ab4 ALSA: dice: use s... |
220 221 |
params->size * i + TX_ISOCHRONOUS, reg, sizeof(reg[0])); |
436b5abe2 ALSA: dice: handl... |
222 223 |
} else { err = snd_dice_transaction_write_rx(dice, |
8cc1a8ab4 ALSA: dice: use s... |
224 225 |
params->size * i + RX_ISOCHRONOUS, reg, sizeof(reg[0])); |
436b5abe2 ALSA: dice: handl... |
226 227 228 229 230 231 232 233 |
} if (err < 0) return err; err = amdtp_stream_start(&streams[i], resources[i].channel, fw_parent_device(dice->unit)->max_speed); if (err < 0) return err; |
288a8d0cb ALSA: dice: Chang... |
234 |
} |
288a8d0cb ALSA: dice: Chang... |
235 236 |
return err; } |
436b5abe2 ALSA: dice: handl... |
237 238 239 240 241 |
/* * MEMO: After this function, there're two states of streams: * - None streams are running. * - All streams are running. */ |
9a02843ca ALSA: dice: Add s... |
242 |
int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) |
288a8d0cb ALSA: dice: Chang... |
243 244 |
{ unsigned int curr_rate; |
436b5abe2 ALSA: dice: handl... |
245 |
unsigned int i; |
8cc1a8ab4 ALSA: dice: use s... |
246 |
struct reg_params tx_params, rx_params; |
436b5abe2 ALSA: dice: handl... |
247 248 |
bool need_to_start; int err; |
9a02843ca ALSA: dice: Add s... |
249 250 |
if (dice->substreams_counter == 0) |
436b5abe2 ALSA: dice: handl... |
251 |
return -EIO; |
288a8d0cb ALSA: dice: Chang... |
252 |
|
8cc1a8ab4 ALSA: dice: use s... |
253 |
err = get_register_params(dice, &tx_params, &rx_params); |
436b5abe2 ALSA: dice: handl... |
254 255 |
if (err < 0) return err; |
288a8d0cb ALSA: dice: Chang... |
256 |
|
288a8d0cb ALSA: dice: Chang... |
257 258 259 260 261 |
err = snd_dice_transaction_get_rate(dice, &curr_rate); if (err < 0) { dev_err(&dice->unit->device, "fail to get sampling rate "); |
436b5abe2 ALSA: dice: handl... |
262 |
return err; |
288a8d0cb ALSA: dice: Chang... |
263 |
} |
a113ff886 ALSA: dice: Add s... |
264 265 |
if (rate == 0) rate = curr_rate; |
436b5abe2 ALSA: dice: handl... |
266 267 268 269 270 |
if (rate != curr_rate) return -EINVAL; /* Judge to need to restart streams. */ for (i = 0; i < MAX_STREAMS; i++) { |
8cc1a8ab4 ALSA: dice: use s... |
271 |
if (i < tx_params.count) { |
436b5abe2 ALSA: dice: handl... |
272 273 274 275 |
if (amdtp_streaming_error(&dice->tx_stream[i]) || !amdtp_stream_running(&dice->tx_stream[i])) break; } |
8cc1a8ab4 ALSA: dice: use s... |
276 |
if (i < rx_params.count) { |
436b5abe2 ALSA: dice: handl... |
277 278 279 280 |
if (amdtp_streaming_error(&dice->rx_stream[i]) || !amdtp_stream_running(&dice->rx_stream[i])) break; } |
1bc8e12d9 ALSA: dice: limit... |
281 |
} |
436b5abe2 ALSA: dice: handl... |
282 |
need_to_start = (i < MAX_STREAMS); |
288a8d0cb ALSA: dice: Chang... |
283 |
|
436b5abe2 ALSA: dice: handl... |
284 285 |
if (need_to_start) { /* Stop transmission. */ |
288a8d0cb ALSA: dice: Chang... |
286 |
snd_dice_transaction_clear_enable(dice); |
8cc1a8ab4 ALSA: dice: use s... |
287 288 |
stop_streams(dice, AMDTP_IN_STREAM, &tx_params); stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
436b5abe2 ALSA: dice: handl... |
289 |
release_resources(dice); |
288a8d0cb ALSA: dice: Chang... |
290 |
|
dfabc0eee ALSA: dice: ensur... |
291 |
err = ensure_phase_lock(dice); |
288a8d0cb ALSA: dice: Chang... |
292 293 |
if (err < 0) { dev_err(&dice->unit->device, |
dfabc0eee ALSA: dice: ensur... |
294 295 |
"fail to ensure phase lock "); |
436b5abe2 ALSA: dice: handl... |
296 |
return err; |
288a8d0cb ALSA: dice: Chang... |
297 |
} |
9a02843ca ALSA: dice: Add s... |
298 |
/* Start both streams. */ |
8cc1a8ab4 ALSA: dice: use s... |
299 |
err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); |
436b5abe2 ALSA: dice: handl... |
300 301 |
if (err < 0) goto error; |
8cc1a8ab4 ALSA: dice: use s... |
302 |
err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); |
436b5abe2 ALSA: dice: handl... |
303 304 |
if (err < 0) goto error; |
288a8d0cb ALSA: dice: Chang... |
305 306 307 308 309 |
err = snd_dice_transaction_set_enable(dice); if (err < 0) { dev_err(&dice->unit->device, "fail to enable interface "); |
436b5abe2 ALSA: dice: handl... |
310 |
goto error; |
288a8d0cb ALSA: dice: Chang... |
311 |
} |
436b5abe2 ALSA: dice: handl... |
312 |
for (i = 0; i < MAX_STREAMS; i++) { |
8cc1a8ab4 ALSA: dice: use s... |
313 |
if ((i < tx_params.count && |
436b5abe2 ALSA: dice: handl... |
314 315 |
!amdtp_stream_wait_callback(&dice->tx_stream[i], CALLBACK_TIMEOUT)) || |
8cc1a8ab4 ALSA: dice: use s... |
316 |
(i < rx_params.count && |
436b5abe2 ALSA: dice: handl... |
317 318 319 320 321 |
!amdtp_stream_wait_callback(&dice->rx_stream[i], CALLBACK_TIMEOUT))) { err = -ETIMEDOUT; goto error; } |
288a8d0cb ALSA: dice: Chang... |
322 323 |
} } |
436b5abe2 ALSA: dice: handl... |
324 325 326 327 |
return err; error: snd_dice_transaction_clear_enable(dice); |
8cc1a8ab4 ALSA: dice: use s... |
328 329 |
stop_streams(dice, AMDTP_IN_STREAM, &tx_params); stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
436b5abe2 ALSA: dice: handl... |
330 |
release_resources(dice); |
288a8d0cb ALSA: dice: Chang... |
331 332 |
return err; } |
436b5abe2 ALSA: dice: handl... |
333 334 335 336 337 |
/* * MEMO: After this function, there're two states of streams: * - None streams are running. * - All streams are running. */ |
9a02843ca ALSA: dice: Add s... |
338 |
void snd_dice_stream_stop_duplex(struct snd_dice *dice) |
288a8d0cb ALSA: dice: Chang... |
339 |
{ |
8cc1a8ab4 ALSA: dice: use s... |
340 |
struct reg_params tx_params, rx_params; |
436b5abe2 ALSA: dice: handl... |
341 |
|
9a02843ca ALSA: dice: Add s... |
342 343 |
if (dice->substreams_counter > 0) return; |
288a8d0cb ALSA: dice: Chang... |
344 |
snd_dice_transaction_clear_enable(dice); |
9a02843ca ALSA: dice: Add s... |
345 |
|
8cc1a8ab4 ALSA: dice: use s... |
346 347 348 |
if (get_register_params(dice, &tx_params, &rx_params) == 0) { stop_streams(dice, AMDTP_IN_STREAM, &tx_params); stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
436b5abe2 ALSA: dice: handl... |
349 350 351 |
} release_resources(dice); |
6eb6c81ee ALSA: dice: Split... |
352 |
} |
436b5abe2 ALSA: dice: handl... |
353 354 |
static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir, unsigned int index) |
6eb6c81ee ALSA: dice: Split... |
355 |
{ |
436b5abe2 ALSA: dice: handl... |
356 |
struct amdtp_stream *stream; |
9a02843ca ALSA: dice: Add s... |
357 |
struct fw_iso_resources *resources; |
436b5abe2 ALSA: dice: handl... |
358 |
int err; |
9a02843ca ALSA: dice: Add s... |
359 |
|
436b5abe2 ALSA: dice: handl... |
360 361 362 |
if (dir == AMDTP_IN_STREAM) { stream = &dice->tx_stream[index]; resources = &dice->tx_resources[index]; |
9a02843ca ALSA: dice: Add s... |
363 |
} else { |
436b5abe2 ALSA: dice: handl... |
364 365 |
stream = &dice->rx_stream[index]; resources = &dice->rx_resources[index]; |
9a02843ca ALSA: dice: Add s... |
366 |
} |
6eb6c81ee ALSA: dice: Split... |
367 |
|
9a02843ca ALSA: dice: Add s... |
368 |
err = fw_iso_resources_init(resources, dice->unit); |
6eb6c81ee ALSA: dice: Split... |
369 370 |
if (err < 0) goto end; |
9a02843ca ALSA: dice: Add s... |
371 |
resources->channels_mask = 0x00000000ffffffffuLL; |
6eb6c81ee ALSA: dice: Split... |
372 |
|
5955815e7 ALSA: firewire-li... |
373 |
err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING); |
9a02843ca ALSA: dice: Add s... |
374 375 376 377 378 379 380 |
if (err < 0) { amdtp_stream_destroy(stream); fw_iso_resources_destroy(resources); } end: return err; } |
d23c2cc44 ALSA: fireworks/b... |
381 382 383 384 |
/* * This function should be called before starting streams or after stopping * streams. */ |
436b5abe2 ALSA: dice: handl... |
385 386 387 |
static void destroy_stream(struct snd_dice *dice, enum amdtp_stream_direction dir, unsigned int index) |
9a02843ca ALSA: dice: Add s... |
388 |
{ |
436b5abe2 ALSA: dice: handl... |
389 |
struct amdtp_stream *stream; |
d23c2cc44 ALSA: fireworks/b... |
390 |
struct fw_iso_resources *resources; |
9a02843ca ALSA: dice: Add s... |
391 |
|
436b5abe2 ALSA: dice: handl... |
392 393 394 395 396 397 398 |
if (dir == AMDTP_IN_STREAM) { stream = &dice->tx_stream[index]; resources = &dice->tx_resources[index]; } else { stream = &dice->rx_stream[index]; resources = &dice->rx_resources[index]; } |
d23c2cc44 ALSA: fireworks/b... |
399 400 401 |
amdtp_stream_destroy(stream); fw_iso_resources_destroy(resources); |
9a02843ca ALSA: dice: Add s... |
402 403 404 405 |
} int snd_dice_stream_init_duplex(struct snd_dice *dice) { |
436b5abe2 ALSA: dice: handl... |
406 |
int i, err; |
9a02843ca ALSA: dice: Add s... |
407 |
|
436b5abe2 ALSA: dice: handl... |
408 409 410 411 412 413 414 415 |
for (i = 0; i < MAX_STREAMS; i++) { err = init_stream(dice, AMDTP_IN_STREAM, i); if (err < 0) { for (; i >= 0; i--) destroy_stream(dice, AMDTP_OUT_STREAM, i); goto end; } } |
6eb6c81ee ALSA: dice: Split... |
416 |
|
436b5abe2 ALSA: dice: handl... |
417 418 419 420 421 422 423 424 425 426 |
for (i = 0; i < MAX_STREAMS; i++) { err = init_stream(dice, AMDTP_OUT_STREAM, i); if (err < 0) { for (; i >= 0; i--) destroy_stream(dice, AMDTP_OUT_STREAM, i); for (i = 0; i < MAX_STREAMS; i++) destroy_stream(dice, AMDTP_IN_STREAM, i); break; } } |
6eb6c81ee ALSA: dice: Split... |
427 428 |
end: return err; |
6eb6c81ee ALSA: dice: Split... |
429 |
} |
9a02843ca ALSA: dice: Add s... |
430 |
void snd_dice_stream_destroy_duplex(struct snd_dice *dice) |
6eb6c81ee ALSA: dice: Split... |
431 |
{ |
6b94fb14f ALSA: dice: fix m... |
432 |
unsigned int i; |
9a02843ca ALSA: dice: Add s... |
433 |
|
6b94fb14f ALSA: dice: fix m... |
434 435 436 |
for (i = 0; i < MAX_STREAMS; i++) { destroy_stream(dice, AMDTP_IN_STREAM, i); destroy_stream(dice, AMDTP_OUT_STREAM, i); |
436b5abe2 ALSA: dice: handl... |
437 |
} |
6eb6c81ee ALSA: dice: Split... |
438 |
} |
9a02843ca ALSA: dice: Add s... |
439 |
void snd_dice_stream_update_duplex(struct snd_dice *dice) |
6eb6c81ee ALSA: dice: Split... |
440 |
{ |
8cc1a8ab4 ALSA: dice: use s... |
441 |
struct reg_params tx_params, rx_params; |
436b5abe2 ALSA: dice: handl... |
442 |
|
6eb6c81ee ALSA: dice: Split... |
443 444 445 446 447 448 449 450 451 |
/* * On a bus reset, the DICE firmware disables streaming and then goes * off contemplating its own navel for hundreds of milliseconds before * it can react to any of our attempts to reenable streaming. This * means that we lose synchronization anyway, so we force our streams * to stop so that the application can restart them in an orderly * manner. */ dice->global_enabled = false; |
8cc1a8ab4 ALSA: dice: use s... |
452 453 454 |
if (get_register_params(dice, &tx_params, &rx_params) == 0) { stop_streams(dice, AMDTP_IN_STREAM, &tx_params); stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); |
436b5abe2 ALSA: dice: handl... |
455 |
} |
6eb6c81ee ALSA: dice: Split... |
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
} static void dice_lock_changed(struct snd_dice *dice) { dice->dev_lock_changed = true; wake_up(&dice->hwdep_wait); } int snd_dice_stream_lock_try(struct snd_dice *dice) { int err; spin_lock_irq(&dice->lock); if (dice->dev_lock_count < 0) { err = -EBUSY; goto out; } if (dice->dev_lock_count++ == 0) dice_lock_changed(dice); err = 0; out: spin_unlock_irq(&dice->lock); return err; } void snd_dice_stream_lock_release(struct snd_dice *dice) { spin_lock_irq(&dice->lock); if (WARN_ON(dice->dev_lock_count <= 0)) goto out; if (--dice->dev_lock_count == 0) dice_lock_changed(dice); out: spin_unlock_irq(&dice->lock); } |