Blame view

sound/firewire/dice/dice-stream.c 12.3 KB
6eb6c81ee   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Chang...
11
  #define	CALLBACK_TIMEOUT	200
dfabc0eee   Takashi Sakamoto   ALSA: dice: ensur...
12
  #define NOTIFICATION_TIMEOUT_MS	(2 * MSEC_PER_SEC)
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
13

8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
14
15
16
17
  struct reg_params {
  	unsigned int count;
  	unsigned int size;
  };
6eb6c81ee   Takashi Sakamoto   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   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: old f...
36
  	__be32 reg, nominal;
dfabc0eee   Takashi Sakamoto   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,
  					       &reg, 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,
  						&reg, sizeof(reg));
  	if (err < 0)
  		return err;
  
  	if (wait_for_completion_timeout(&dice->clock_accepted,
fbeac84db   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: ensur...
66
67
68
  
  	return 0;
  }
8cc1a8ab4   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Split...
72
  {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
73
  	__be32 reg[2];
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
74
  	int err;
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
75
  	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
76
  	if (err < 0)
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
77
  		return err;
8cc1a8ab4   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Split...
81

436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
82
  	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
83
  	if (err < 0)
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
84
  		return err;
8cc1a8ab4   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: handl...
88
89
  
  	return 0;
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
90
  }
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
91
  static void release_resources(struct snd_dice *dice)
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
92
  {
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Split...
104

436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
105
106
107
  		fw_iso_resources_free(&dice->tx_resources[i]);
  		fw_iso_resources_free(&dice->rx_resources[i]);
  	}
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
108
  }
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
109
  static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
110
  			 struct reg_params *params)
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
111
  {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
112
113
  	__be32 reg;
  	unsigned int i;
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
114
  	for (i = 0; i < params->count; i++) {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
115
116
117
  		reg = cpu_to_be32((u32)-1);
  		if (dir == AMDTP_IN_STREAM) {
  			snd_dice_transaction_write_tx(dice,
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
118
119
  					params->size * i + TX_ISOCHRONOUS,
  					&reg, sizeof(reg));
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
120
121
  		} else {
  			snd_dice_transaction_write_rx(dice,
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
122
123
  					params->size * i + RX_ISOCHRONOUS,
  					&reg, sizeof(reg));
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Add s...
134
  	struct fw_iso_resources *resources;
27ec83b5c   Takashi Sakamoto   ALSA: firewire-li...
135
  	bool double_pcm_frames;
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
136
  	unsigned int i;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
137
  	int err;
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
138

436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
139
140
141
  	if (dir == AMDTP_IN_STREAM) {
  		stream = &dice->tx_stream[index];
  		resources = &dice->tx_resources[index];
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
142
  	} else {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
143
144
  		stream = &dice->rx_stream[index];
  		resources = &dice->rx_resources[index];
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
145
  	}
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
146

288a8d0cb   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: purge...
157
  	double_pcm_frames = rate > 96000;
27ec83b5c   Takashi Sakamoto   ALSA: firewire-li...
158
  	if (double_pcm_frames) {
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
159
160
  		rate /= 2;
  		pcm_chs *= 2;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
161
  	}
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
162

51c29fd21   Takashi Sakamoto   ALSA: firewire-li...
163
164
  	err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
  					 double_pcm_frames);
547e631ce   Takashi Sakamoto   ALSA: firewire-li...
165
  	if (err < 0)
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
166
  		return err;
547e631ce   Takashi Sakamoto   ALSA: firewire-li...
167

27ec83b5c   Takashi Sakamoto   ALSA: firewire-li...
168
  	if (double_pcm_frames) {
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
169
  		pcm_chs /= 2;
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
170

288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
171
  		for (i = 0; i < pcm_chs; i++) {
f65be911c   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Chang...
175
176
  		}
  	}
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: use s...
183
  			 unsigned int rate, struct reg_params *params)
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: use s...
198
  	for (i = 0; i < params->count; i++) {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
199
200
  		if (dir == AMDTP_IN_STREAM) {
  			err = snd_dice_transaction_read_tx(dice,
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
201
202
  					params->size * i + TX_NUMBER_AUDIO,
  					reg, sizeof(reg));
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
203
204
  		} else {
  			err = snd_dice_transaction_read_rx(dice,
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
205
206
  					params->size * i + RX_NUMBER_AUDIO,
  					reg, sizeof(reg));
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: use s...
220
221
  					params->size * i + TX_ISOCHRONOUS,
  					reg, sizeof(reg[0]));
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
222
223
  		} else {
  			err = snd_dice_transaction_write_rx(dice,
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
224
225
  					params->size * i + RX_ISOCHRONOUS,
  					reg, sizeof(reg[0]));
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Chang...
234
  	}
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
235
236
  	return err;
  }
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Add s...
242
  int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
243
244
  {
  	unsigned int curr_rate;
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
245
  	unsigned int i;
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
246
  	struct reg_params tx_params, rx_params;
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
247
248
  	bool need_to_start;
  	int err;
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
249
250
  
  	if (dice->substreams_counter == 0)
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
251
  		return -EIO;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
252

8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
253
  	err = get_register_params(dice, &tx_params, &rx_params);
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
254
255
  	if (err < 0)
  		return err;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
256

288a8d0cb   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: handl...
262
  		return err;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
263
  	}
a113ff886   Takashi Sakamoto   ALSA: dice: Add s...
264
265
  	if (rate == 0)
  		rate = curr_rate;
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: use s...
271
  		if (i < tx_params.count) {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
272
273
274
275
  			if (amdtp_streaming_error(&dice->tx_stream[i]) ||
  			    !amdtp_stream_running(&dice->tx_stream[i]))
  				break;
  		}
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
276
  		if (i < rx_params.count) {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
277
278
279
280
  			if (amdtp_streaming_error(&dice->rx_stream[i]) ||
  			    !amdtp_stream_running(&dice->rx_stream[i]))
  				break;
  		}
1bc8e12d9   Takashi Sakamoto   ALSA: dice: limit...
281
  	}
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
282
  	need_to_start = (i < MAX_STREAMS);
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
283

436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
284
285
  	if (need_to_start) {
  		/* Stop transmission. */
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
286
  		snd_dice_transaction_clear_enable(dice);
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
287
288
  		stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
  		stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
289
  		release_resources(dice);
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
290

dfabc0eee   Takashi Sakamoto   ALSA: dice: ensur...
291
  		err = ensure_phase_lock(dice);
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
292
293
  		if (err < 0) {
  			dev_err(&dice->unit->device,
dfabc0eee   Takashi Sakamoto   ALSA: dice: ensur...
294
295
  				"fail to ensure phase lock
  ");
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
296
  			return err;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
297
  		}
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
298
  		/* Start both streams. */
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
299
  		err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
300
301
  		if (err < 0)
  			goto error;
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
302
  		err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
303
304
  		if (err < 0)
  			goto error;
288a8d0cb   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: handl...
310
  			goto error;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
311
  		}
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
312
  		for (i = 0; i < MAX_STREAMS; i++) {
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
313
  			if ((i < tx_params.count &&
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
314
315
  			    !amdtp_stream_wait_callback(&dice->tx_stream[i],
  							CALLBACK_TIMEOUT)) ||
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
316
  			    (i < rx_params.count &&
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
317
318
319
320
321
  			     !amdtp_stream_wait_callback(&dice->rx_stream[i],
  							 CALLBACK_TIMEOUT))) {
  				err = -ETIMEDOUT;
  				goto error;
  			}
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
322
323
  		}
  	}
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
324
325
326
327
  
  	return err;
  error:
  	snd_dice_transaction_clear_enable(dice);
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
328
329
  	stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
  	stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
330
  	release_resources(dice);
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
331
332
  	return err;
  }
436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Add s...
338
  void snd_dice_stream_stop_duplex(struct snd_dice *dice)
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
339
  {
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
340
  	struct reg_params tx_params, rx_params;
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
341

9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
342
343
  	if (dice->substreams_counter > 0)
  		return;
288a8d0cb   Takashi Sakamoto   ALSA: dice: Chang...
344
  	snd_dice_transaction_clear_enable(dice);
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
345

8cc1a8ab4   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: handl...
349
350
351
  	}
  
  	release_resources(dice);
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
352
  }
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
353
354
  static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
  		       unsigned int index)
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
355
  {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
356
  	struct amdtp_stream *stream;
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
357
  	struct fw_iso_resources *resources;
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
358
  	int err;
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
359

436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
360
361
362
  	if (dir == AMDTP_IN_STREAM) {
  		stream = &dice->tx_stream[index];
  		resources = &dice->tx_resources[index];
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
363
  	} else {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
364
365
  		stream = &dice->rx_stream[index];
  		resources = &dice->rx_resources[index];
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
366
  	}
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
367

9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
368
  	err = fw_iso_resources_init(resources, dice->unit);
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
369
370
  	if (err < 0)
  		goto end;
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
371
  	resources->channels_mask = 0x00000000ffffffffuLL;
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
372

5955815e7   Takashi Sakamoto   ALSA: firewire-li...
373
  	err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
9a02843ca   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: fireworks/b...
381
382
383
384
  /*
   * This function should be called before starting streams or after stopping
   * streams.
   */
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
385
386
387
  static void destroy_stream(struct snd_dice *dice,
  			   enum amdtp_stream_direction dir,
  			   unsigned int index)
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
388
  {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
389
  	struct amdtp_stream *stream;
d23c2cc44   Takashi Sakamoto   ALSA: fireworks/b...
390
  	struct fw_iso_resources *resources;
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
391

436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: fireworks/b...
399
400
401
  
  	amdtp_stream_destroy(stream);
  	fw_iso_resources_destroy(resources);
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
402
403
404
405
  }
  
  int snd_dice_stream_init_duplex(struct snd_dice *dice)
  {
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
406
  	int i, err;
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
407

436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Split...
416

436b5abe2   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: Split...
427
428
  end:
  	return err;
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
429
  }
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
430
  void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
431
  {
6b94fb14f   Takashi Sakamoto   ALSA: dice: fix m...
432
  	unsigned int i;
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
433

6b94fb14f   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: handl...
437
  	}
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
438
  }
9a02843ca   Takashi Sakamoto   ALSA: dice: Add s...
439
  void snd_dice_stream_update_duplex(struct snd_dice *dice)
6eb6c81ee   Takashi Sakamoto   ALSA: dice: Split...
440
  {
8cc1a8ab4   Takashi Sakamoto   ALSA: dice: use s...
441
  	struct reg_params tx_params, rx_params;
436b5abe2   Takashi Sakamoto   ALSA: dice: handl...
442

6eb6c81ee   Takashi Sakamoto   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   Takashi Sakamoto   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   Takashi Sakamoto   ALSA: dice: handl...
455
  	}
6eb6c81ee   Takashi Sakamoto   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);
  }