Commit | Line | Data |
---|---|---|
6eb6c81e TS |
1 | /* |
2 | * dice_stream.c - a part of driver for DICE based devices | |
3 | * | |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | |
5 | * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> | |
6 | * | |
7 | * Licensed under the terms of the GNU General Public License, version 2. | |
8 | */ | |
9 | ||
10 | #include "dice.h" | |
11 | ||
288a8d0c TS |
12 | #define CALLBACK_TIMEOUT 200 |
13 | ||
6eb6c81e TS |
14 | const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { |
15 | /* mode 0 */ | |
16 | [0] = 32000, | |
17 | [1] = 44100, | |
18 | [2] = 48000, | |
19 | /* mode 1 */ | |
20 | [3] = 88200, | |
21 | [4] = 96000, | |
22 | /* mode 2 */ | |
23 | [5] = 176400, | |
24 | [6] = 192000, | |
25 | }; | |
26 | ||
27 | int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, | |
28 | unsigned int *mode) | |
29 | { | |
30 | int i; | |
31 | ||
32 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { | |
33 | if (!(dice->clock_caps & BIT(i))) | |
34 | continue; | |
35 | if (snd_dice_rates[i] != rate) | |
36 | continue; | |
37 | ||
38 | *mode = (i - 1) / 2; | |
39 | return 0; | |
40 | } | |
41 | return -EINVAL; | |
42 | } | |
43 | ||
9a02843c TS |
44 | static void release_resources(struct snd_dice *dice, |
45 | struct fw_iso_resources *resources) | |
6eb6c81e | 46 | { |
3e93d42a | 47 | __be32 channel; |
6eb6c81e | 48 | |
288a8d0c TS |
49 | /* Reset channel number */ |
50 | channel = cpu_to_be32((u32)-1); | |
9a02843c TS |
51 | if (resources == &dice->tx_resources) |
52 | snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS, | |
3e93d42a | 53 | &channel, sizeof(channel)); |
9a02843c TS |
54 | else |
55 | snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, | |
3e93d42a | 56 | &channel, sizeof(channel)); |
9a02843c TS |
57 | |
58 | fw_iso_resources_free(resources); | |
6eb6c81e TS |
59 | } |
60 | ||
9a02843c TS |
61 | static int keep_resources(struct snd_dice *dice, |
62 | struct fw_iso_resources *resources, | |
63 | unsigned int max_payload_bytes) | |
6eb6c81e | 64 | { |
3e93d42a | 65 | __be32 channel; |
6eb6c81e TS |
66 | int err; |
67 | ||
9a02843c | 68 | err = fw_iso_resources_allocate(resources, max_payload_bytes, |
6eb6c81e | 69 | fw_parent_device(dice->unit)->max_speed); |
6eb6c81e | 70 | if (err < 0) |
288a8d0c | 71 | goto end; |
6eb6c81e | 72 | |
288a8d0c | 73 | /* Set channel number */ |
9a02843c TS |
74 | channel = cpu_to_be32(resources->channel); |
75 | if (resources == &dice->tx_resources) | |
76 | err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS, | |
3e93d42a | 77 | &channel, sizeof(channel)); |
9a02843c TS |
78 | else |
79 | err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, | |
3e93d42a | 80 | &channel, sizeof(channel)); |
288a8d0c | 81 | if (err < 0) |
9a02843c | 82 | release_resources(dice, resources); |
288a8d0c | 83 | end: |
6eb6c81e TS |
84 | return err; |
85 | } | |
86 | ||
9a02843c | 87 | static void stop_stream(struct snd_dice *dice, struct amdtp_stream *stream) |
6eb6c81e | 88 | { |
9a02843c TS |
89 | amdtp_stream_pcm_abort(stream); |
90 | amdtp_stream_stop(stream); | |
c50fb91f | 91 | |
9a02843c TS |
92 | if (stream == &dice->tx_stream) |
93 | release_resources(dice, &dice->tx_resources); | |
94 | else | |
95 | release_resources(dice, &dice->rx_resources); | |
6eb6c81e TS |
96 | } |
97 | ||
9a02843c TS |
98 | static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, |
99 | unsigned int rate) | |
6eb6c81e | 100 | { |
9a02843c | 101 | struct fw_iso_resources *resources; |
288a8d0c | 102 | unsigned int i, mode, pcm_chs, midi_ports; |
27ec83b5 | 103 | bool double_pcm_frames; |
288a8d0c | 104 | int err; |
6eb6c81e | 105 | |
288a8d0c TS |
106 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); |
107 | if (err < 0) | |
108 | goto end; | |
9a02843c TS |
109 | if (stream == &dice->tx_stream) { |
110 | resources = &dice->tx_resources; | |
111 | pcm_chs = dice->tx_channels[mode]; | |
112 | midi_ports = dice->tx_midi_ports[mode]; | |
113 | } else { | |
114 | resources = &dice->rx_resources; | |
115 | pcm_chs = dice->rx_channels[mode]; | |
116 | midi_ports = dice->rx_midi_ports[mode]; | |
117 | } | |
6eb6c81e | 118 | |
288a8d0c TS |
119 | /* |
120 | * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in | |
121 | * one data block of AMDTP packet. Thus sampling transfer frequency is | |
122 | * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are | |
123 | * transferred on AMDTP packets at 96 kHz. Two successive samples of a | |
124 | * channel are stored consecutively in the packet. This quirk is called | |
125 | * as 'Dual Wire'. | |
126 | * For this quirk, blocking mode is required and PCM buffer size should | |
127 | * be aligned to SYT_INTERVAL. | |
128 | */ | |
27ec83b5 TS |
129 | double_pcm_frames = mode > 1; |
130 | if (double_pcm_frames) { | |
288a8d0c TS |
131 | rate /= 2; |
132 | pcm_chs *= 2; | |
288a8d0c | 133 | } |
6eb6c81e | 134 | |
51c29fd2 TS |
135 | err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports, |
136 | double_pcm_frames); | |
547e631c TS |
137 | if (err < 0) |
138 | goto end; | |
139 | ||
27ec83b5 | 140 | if (double_pcm_frames) { |
288a8d0c | 141 | pcm_chs /= 2; |
6eb6c81e | 142 | |
288a8d0c | 143 | for (i = 0; i < pcm_chs; i++) { |
f65be911 TS |
144 | amdtp_am824_set_pcm_position(stream, i, i * 2); |
145 | amdtp_am824_set_pcm_position(stream, i + pcm_chs, | |
146 | i * 2 + 1); | |
288a8d0c TS |
147 | } |
148 | } | |
149 | ||
9a02843c TS |
150 | err = keep_resources(dice, resources, |
151 | amdtp_stream_get_max_payload(stream)); | |
288a8d0c TS |
152 | if (err < 0) { |
153 | dev_err(&dice->unit->device, | |
154 | "fail to keep isochronous resources\n"); | |
155 | goto end; | |
156 | } | |
157 | ||
9a02843c | 158 | err = amdtp_stream_start(stream, resources->channel, |
288a8d0c TS |
159 | fw_parent_device(dice->unit)->max_speed); |
160 | if (err < 0) | |
9a02843c | 161 | release_resources(dice, resources); |
288a8d0c TS |
162 | end: |
163 | return err; | |
164 | } | |
165 | ||
9a02843c TS |
166 | static int get_sync_mode(struct snd_dice *dice, enum cip_flags *sync_mode) |
167 | { | |
8fc01fc0 TS |
168 | u32 source; |
169 | int err; | |
170 | ||
171 | err = snd_dice_transaction_get_clock_source(dice, &source); | |
172 | if (err < 0) | |
173 | goto end; | |
174 | ||
175 | switch (source) { | |
176 | /* So-called 'SYT Match' modes, sync_to_syt value of packets received */ | |
177 | case CLOCK_SOURCE_ARX4: /* in 4th stream */ | |
178 | case CLOCK_SOURCE_ARX3: /* in 3rd stream */ | |
179 | case CLOCK_SOURCE_ARX2: /* in 2nd stream */ | |
180 | err = -ENOSYS; | |
181 | break; | |
182 | case CLOCK_SOURCE_ARX1: /* in 1st stream, which this driver uses */ | |
183 | *sync_mode = 0; | |
184 | break; | |
185 | default: | |
186 | *sync_mode = CIP_SYNC_TO_DEVICE; | |
187 | break; | |
188 | } | |
189 | end: | |
190 | return err; | |
9a02843c TS |
191 | } |
192 | ||
193 | int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) | |
288a8d0c | 194 | { |
9a02843c | 195 | struct amdtp_stream *master, *slave; |
288a8d0c | 196 | unsigned int curr_rate; |
9a02843c TS |
197 | enum cip_flags sync_mode; |
198 | int err = 0; | |
199 | ||
200 | if (dice->substreams_counter == 0) | |
201 | goto end; | |
202 | ||
203 | err = get_sync_mode(dice, &sync_mode); | |
204 | if (err < 0) | |
205 | goto end; | |
206 | if (sync_mode == CIP_SYNC_TO_DEVICE) { | |
207 | master = &dice->tx_stream; | |
208 | slave = &dice->rx_stream; | |
209 | } else { | |
210 | master = &dice->rx_stream; | |
211 | slave = &dice->tx_stream; | |
212 | } | |
288a8d0c TS |
213 | |
214 | /* Some packet queueing errors. */ | |
9a02843c TS |
215 | if (amdtp_streaming_error(master) || amdtp_streaming_error(slave)) |
216 | stop_stream(dice, master); | |
288a8d0c TS |
217 | |
218 | /* Stop stream if rate is different. */ | |
219 | err = snd_dice_transaction_get_rate(dice, &curr_rate); | |
220 | if (err < 0) { | |
221 | dev_err(&dice->unit->device, | |
222 | "fail to get sampling rate\n"); | |
223 | goto end; | |
224 | } | |
a113ff88 TS |
225 | if (rate == 0) |
226 | rate = curr_rate; | |
288a8d0c | 227 | if (rate != curr_rate) |
9a02843c | 228 | stop_stream(dice, master); |
288a8d0c | 229 | |
9a02843c TS |
230 | if (!amdtp_stream_running(master)) { |
231 | stop_stream(dice, slave); | |
288a8d0c TS |
232 | snd_dice_transaction_clear_enable(dice); |
233 | ||
9a02843c TS |
234 | amdtp_stream_set_sync(sync_mode, master, slave); |
235 | ||
288a8d0c TS |
236 | err = snd_dice_transaction_set_rate(dice, rate); |
237 | if (err < 0) { | |
238 | dev_err(&dice->unit->device, | |
239 | "fail to set sampling rate\n"); | |
240 | goto end; | |
241 | } | |
242 | ||
9a02843c TS |
243 | /* Start both streams. */ |
244 | err = start_stream(dice, master, rate); | |
245 | if (err < 0) { | |
246 | dev_err(&dice->unit->device, | |
247 | "fail to start AMDTP master stream\n"); | |
248 | goto end; | |
249 | } | |
250 | err = start_stream(dice, slave, rate); | |
288a8d0c TS |
251 | if (err < 0) { |
252 | dev_err(&dice->unit->device, | |
9a02843c TS |
253 | "fail to start AMDTP slave stream\n"); |
254 | stop_stream(dice, master); | |
288a8d0c TS |
255 | goto end; |
256 | } | |
257 | err = snd_dice_transaction_set_enable(dice); | |
258 | if (err < 0) { | |
259 | dev_err(&dice->unit->device, | |
260 | "fail to enable interface\n"); | |
9a02843c TS |
261 | stop_stream(dice, master); |
262 | stop_stream(dice, slave); | |
288a8d0c TS |
263 | goto end; |
264 | } | |
265 | ||
9a02843c TS |
266 | /* Wait first callbacks */ |
267 | if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT) || | |
268 | !amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) { | |
288a8d0c | 269 | snd_dice_transaction_clear_enable(dice); |
9a02843c TS |
270 | stop_stream(dice, master); |
271 | stop_stream(dice, slave); | |
288a8d0c TS |
272 | err = -ETIMEDOUT; |
273 | } | |
274 | } | |
275 | end: | |
276 | return err; | |
277 | } | |
278 | ||
9a02843c | 279 | void snd_dice_stream_stop_duplex(struct snd_dice *dice) |
288a8d0c | 280 | { |
9a02843c TS |
281 | if (dice->substreams_counter > 0) |
282 | return; | |
283 | ||
288a8d0c | 284 | snd_dice_transaction_clear_enable(dice); |
9a02843c TS |
285 | |
286 | stop_stream(dice, &dice->tx_stream); | |
287 | stop_stream(dice, &dice->rx_stream); | |
6eb6c81e TS |
288 | } |
289 | ||
9a02843c | 290 | static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream) |
6eb6c81e TS |
291 | { |
292 | int err; | |
9a02843c TS |
293 | struct fw_iso_resources *resources; |
294 | enum amdtp_stream_direction dir; | |
295 | ||
296 | if (stream == &dice->tx_stream) { | |
297 | resources = &dice->tx_resources; | |
298 | dir = AMDTP_IN_STREAM; | |
299 | } else { | |
300 | resources = &dice->rx_resources; | |
301 | dir = AMDTP_OUT_STREAM; | |
302 | } | |
6eb6c81e | 303 | |
9a02843c | 304 | err = fw_iso_resources_init(resources, dice->unit); |
6eb6c81e TS |
305 | if (err < 0) |
306 | goto end; | |
9a02843c | 307 | resources->channels_mask = 0x00000000ffffffffuLL; |
6eb6c81e | 308 | |
5955815e | 309 | err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING); |
9a02843c TS |
310 | if (err < 0) { |
311 | amdtp_stream_destroy(stream); | |
312 | fw_iso_resources_destroy(resources); | |
313 | } | |
314 | end: | |
315 | return err; | |
316 | } | |
317 | ||
d23c2cc4 TS |
318 | /* |
319 | * This function should be called before starting streams or after stopping | |
320 | * streams. | |
321 | */ | |
9a02843c TS |
322 | static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream) |
323 | { | |
d23c2cc4 | 324 | struct fw_iso_resources *resources; |
9a02843c TS |
325 | |
326 | if (stream == &dice->tx_stream) | |
d23c2cc4 | 327 | resources = &dice->tx_resources; |
9a02843c | 328 | else |
d23c2cc4 TS |
329 | resources = &dice->rx_resources; |
330 | ||
331 | amdtp_stream_destroy(stream); | |
332 | fw_iso_resources_destroy(resources); | |
9a02843c TS |
333 | } |
334 | ||
335 | int snd_dice_stream_init_duplex(struct snd_dice *dice) | |
336 | { | |
337 | int err; | |
338 | ||
339 | dice->substreams_counter = 0; | |
340 | ||
341 | err = init_stream(dice, &dice->tx_stream); | |
6eb6c81e | 342 | if (err < 0) |
9a02843c | 343 | goto end; |
6eb6c81e | 344 | |
9a02843c | 345 | err = init_stream(dice, &dice->rx_stream); |
d23c2cc4 TS |
346 | if (err < 0) |
347 | destroy_stream(dice, &dice->tx_stream); | |
6eb6c81e TS |
348 | end: |
349 | return err; | |
6eb6c81e TS |
350 | } |
351 | ||
9a02843c | 352 | void snd_dice_stream_destroy_duplex(struct snd_dice *dice) |
6eb6c81e | 353 | { |
288a8d0c | 354 | snd_dice_transaction_clear_enable(dice); |
9a02843c | 355 | |
9a02843c | 356 | destroy_stream(dice, &dice->tx_stream); |
9a02843c TS |
357 | destroy_stream(dice, &dice->rx_stream); |
358 | ||
359 | dice->substreams_counter = 0; | |
6eb6c81e TS |
360 | } |
361 | ||
9a02843c | 362 | void snd_dice_stream_update_duplex(struct snd_dice *dice) |
6eb6c81e TS |
363 | { |
364 | /* | |
365 | * On a bus reset, the DICE firmware disables streaming and then goes | |
366 | * off contemplating its own navel for hundreds of milliseconds before | |
367 | * it can react to any of our attempts to reenable streaming. This | |
368 | * means that we lose synchronization anyway, so we force our streams | |
369 | * to stop so that the application can restart them in an orderly | |
370 | * manner. | |
371 | */ | |
372 | dice->global_enabled = false; | |
373 | ||
9a02843c TS |
374 | stop_stream(dice, &dice->rx_stream); |
375 | stop_stream(dice, &dice->tx_stream); | |
288a8d0c | 376 | |
6eb6c81e | 377 | fw_iso_resources_update(&dice->rx_resources); |
9a02843c | 378 | fw_iso_resources_update(&dice->tx_resources); |
6eb6c81e TS |
379 | } |
380 | ||
381 | static void dice_lock_changed(struct snd_dice *dice) | |
382 | { | |
383 | dice->dev_lock_changed = true; | |
384 | wake_up(&dice->hwdep_wait); | |
385 | } | |
386 | ||
387 | int snd_dice_stream_lock_try(struct snd_dice *dice) | |
388 | { | |
389 | int err; | |
390 | ||
391 | spin_lock_irq(&dice->lock); | |
392 | ||
393 | if (dice->dev_lock_count < 0) { | |
394 | err = -EBUSY; | |
395 | goto out; | |
396 | } | |
397 | ||
398 | if (dice->dev_lock_count++ == 0) | |
399 | dice_lock_changed(dice); | |
400 | err = 0; | |
401 | out: | |
402 | spin_unlock_irq(&dice->lock); | |
403 | return err; | |
404 | } | |
405 | ||
406 | void snd_dice_stream_lock_release(struct snd_dice *dice) | |
407 | { | |
408 | spin_lock_irq(&dice->lock); | |
409 | ||
410 | if (WARN_ON(dice->dev_lock_count <= 0)) | |
411 | goto out; | |
412 | ||
413 | if (--dice->dev_lock_count == 0) | |
414 | dice_lock_changed(dice); | |
415 | out: | |
416 | spin_unlock_irq(&dice->lock); | |
417 | } |