diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/firewire/dice/dice-pcm.c | 75 | ||||
-rw-r--r-- | sound/firewire/dice/dice-stream.c | 191 | ||||
-rw-r--r-- | sound/firewire/dice/dice.c | 4 | ||||
-rw-r--r-- | sound/firewire/dice/dice.h | 4 |
4 files changed, 143 insertions, 131 deletions
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 2e531bd30e28..b185391dc021 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c | |||
@@ -169,65 +169,11 @@ static int playback_hw_params(struct snd_pcm_substream *substream, | |||
169 | struct snd_pcm_hw_params *hw_params) | 169 | struct snd_pcm_hw_params *hw_params) |
170 | { | 170 | { |
171 | struct snd_dice *dice = substream->private_data; | 171 | struct snd_dice *dice = substream->private_data; |
172 | unsigned int mode, rate, channels, i; | ||
173 | int err; | ||
174 | |||
175 | mutex_lock(&dice->mutex); | ||
176 | snd_dice_stream_stop(dice); | ||
177 | mutex_unlock(&dice->mutex); | ||
178 | |||
179 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
180 | params_buffer_bytes(hw_params)); | ||
181 | if (err < 0) | ||
182 | return err; | ||
183 | |||
184 | rate = params_rate(hw_params); | ||
185 | err = snd_dice_transaction_set_rate(dice, rate); | ||
186 | if (err < 0) | ||
187 | return err; | ||
188 | |||
189 | if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) | ||
190 | return err; | ||
191 | |||
192 | /* | ||
193 | * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in | ||
194 | * one data block of AMDTP packet. Thus sampling transfer frequency is | ||
195 | * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are | ||
196 | * transferred on AMDTP packets at 96 kHz. Two successive samples of a | ||
197 | * channel are stored consecutively in the packet. This quirk is called | ||
198 | * as 'Dual Wire'. | ||
199 | * For this quirk, blocking mode is required and PCM buffer size should | ||
200 | * be aligned to SYT_INTERVAL. | ||
201 | */ | ||
202 | channels = params_channels(hw_params); | ||
203 | if (mode > 1) { | ||
204 | if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { | ||
205 | err = -ENOSYS; | ||
206 | return err; | ||
207 | } | ||
208 | |||
209 | rate /= 2; | ||
210 | channels *= 2; | ||
211 | dice->rx_stream.double_pcm_frames = true; | ||
212 | } else { | ||
213 | dice->rx_stream.double_pcm_frames = false; | ||
214 | } | ||
215 | |||
216 | amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, | ||
217 | dice->rx_midi_ports[mode]); | ||
218 | if (mode > 1) { | ||
219 | channels /= 2; | ||
220 | |||
221 | for (i = 0; i < channels; i++) { | ||
222 | dice->rx_stream.pcm_positions[i] = i * 2; | ||
223 | dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | amdtp_stream_set_pcm_format(&dice->rx_stream, | 172 | amdtp_stream_set_pcm_format(&dice->rx_stream, |
228 | params_format(hw_params)); | 173 | params_format(hw_params)); |
229 | 174 | ||
230 | return 0; | 175 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, |
176 | params_buffer_bytes(hw_params)); | ||
231 | } | 177 | } |
232 | 178 | ||
233 | static int playback_hw_free(struct snd_pcm_substream *substream) | 179 | static int playback_hw_free(struct snd_pcm_substream *substream) |
@@ -247,21 +193,12 @@ static int playback_prepare(struct snd_pcm_substream *substream) | |||
247 | int err; | 193 | int err; |
248 | 194 | ||
249 | mutex_lock(&dice->mutex); | 195 | mutex_lock(&dice->mutex); |
250 | 196 | err = snd_dice_stream_start(dice, substream->runtime->rate); | |
251 | if (amdtp_streaming_error(&dice->rx_stream)) | ||
252 | snd_dice_stream_stop_packets(dice); | ||
253 | |||
254 | err = snd_dice_stream_start(dice); | ||
255 | if (err < 0) { | ||
256 | mutex_unlock(&dice->mutex); | ||
257 | return err; | ||
258 | } | ||
259 | |||
260 | mutex_unlock(&dice->mutex); | 197 | mutex_unlock(&dice->mutex); |
198 | if (err >= 0) | ||
199 | amdtp_stream_pcm_prepare(&dice->rx_stream); | ||
261 | 200 | ||
262 | amdtp_stream_pcm_prepare(&dice->rx_stream); | 201 | return err; |
263 | |||
264 | return 0; | ||
265 | } | 202 | } |
266 | 203 | ||
267 | static int playback_trigger(struct snd_pcm_substream *substream, int cmd) | 204 | static int playback_trigger(struct snd_pcm_substream *substream, int cmd) |
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 4c4c4fff6272..b9d7a4846459 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c | |||
@@ -9,6 +9,8 @@ | |||
9 | 9 | ||
10 | #include "dice.h" | 10 | #include "dice.h" |
11 | 11 | ||
12 | #define CALLBACK_TIMEOUT 200 | ||
13 | |||
12 | const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { | 14 | const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { |
13 | /* mode 0 */ | 15 | /* mode 0 */ |
14 | [0] = 32000, | 16 | [0] = 32000, |
@@ -39,83 +41,162 @@ int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, | |||
39 | return -EINVAL; | 41 | return -EINVAL; |
40 | } | 42 | } |
41 | 43 | ||
42 | int snd_dice_stream_start_packets(struct snd_dice *dice) | 44 | static void release_resources(struct snd_dice *dice) |
43 | { | 45 | { |
44 | int err; | 46 | unsigned int channel; |
45 | 47 | ||
46 | if (amdtp_stream_running(&dice->rx_stream)) | 48 | /* Reset channel number */ |
47 | return 0; | 49 | channel = cpu_to_be32((u32)-1); |
48 | 50 | snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); | |
49 | err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, | ||
50 | fw_parent_device(dice->unit)->max_speed); | ||
51 | if (err < 0) | ||
52 | return err; | ||
53 | |||
54 | err = snd_dice_transaction_set_enable(dice); | ||
55 | if (err < 0) { | ||
56 | amdtp_stream_stop(&dice->rx_stream); | ||
57 | return err; | ||
58 | } | ||
59 | 51 | ||
60 | return 0; | 52 | fw_iso_resources_free(&dice->rx_resources); |
61 | } | 53 | } |
62 | 54 | ||
63 | int snd_dice_stream_start(struct snd_dice *dice) | 55 | static int keep_resources(struct snd_dice *dice, unsigned int max_payload_bytes) |
64 | { | 56 | { |
65 | __be32 channel; | 57 | unsigned int channel; |
66 | int err; | 58 | int err; |
67 | 59 | ||
68 | if (!dice->rx_resources.allocated) { | 60 | err = fw_iso_resources_allocate(&dice->rx_resources, max_payload_bytes, |
69 | err = fw_iso_resources_allocate(&dice->rx_resources, | ||
70 | amdtp_stream_get_max_payload(&dice->rx_stream), | ||
71 | fw_parent_device(dice->unit)->max_speed); | 61 | fw_parent_device(dice->unit)->max_speed); |
72 | if (err < 0) | ||
73 | goto error; | ||
74 | |||
75 | channel = cpu_to_be32(dice->rx_resources.channel); | ||
76 | err = snd_dice_transaction_write_tx(dice, RX_ISOCHRONOUS, | ||
77 | &channel, 4); | ||
78 | if (err < 0) | ||
79 | goto err_resources; | ||
80 | } | ||
81 | |||
82 | err = snd_dice_stream_start_packets(dice); | ||
83 | if (err < 0) | 62 | if (err < 0) |
84 | goto err_rx_channel; | 63 | goto end; |
85 | |||
86 | return 0; | ||
87 | 64 | ||
88 | err_rx_channel: | 65 | /* Set channel number */ |
89 | channel = cpu_to_be32((u32)-1); | 66 | channel = cpu_to_be32(dice->rx_resources.channel); |
90 | snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); | 67 | err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, |
91 | err_resources: | 68 | &channel, 4); |
92 | fw_iso_resources_free(&dice->rx_resources); | 69 | if (err < 0) |
93 | error: | 70 | release_resources(dice); |
71 | end: | ||
94 | return err; | 72 | return err; |
95 | } | 73 | } |
96 | 74 | ||
97 | void snd_dice_stream_stop_packets(struct snd_dice *dice) | 75 | static void stop_stream(struct snd_dice *dice) |
98 | { | 76 | { |
99 | if (!amdtp_stream_running(&dice->rx_stream)) | 77 | if (!amdtp_stream_running(&dice->rx_stream)) |
100 | return; | 78 | return; |
101 | 79 | ||
102 | snd_dice_transaction_clear_enable(dice); | 80 | amdtp_stream_pcm_abort(&dice->rx_stream); |
103 | amdtp_stream_stop(&dice->rx_stream); | 81 | amdtp_stream_stop(&dice->rx_stream); |
82 | release_resources(dice); | ||
104 | } | 83 | } |
105 | 84 | ||
106 | void snd_dice_stream_stop(struct snd_dice *dice) | 85 | static int start_stream(struct snd_dice *dice, unsigned int rate) |
107 | { | 86 | { |
108 | __be32 channel; | 87 | unsigned int i, mode, pcm_chs, midi_ports; |
88 | int err; | ||
109 | 89 | ||
110 | snd_dice_stream_stop_packets(dice); | 90 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); |
91 | if (err < 0) | ||
92 | goto end; | ||
111 | 93 | ||
112 | if (!dice->rx_resources.allocated) | 94 | /* |
113 | return; | 95 | * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in |
96 | * one data block of AMDTP packet. Thus sampling transfer frequency is | ||
97 | * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are | ||
98 | * transferred on AMDTP packets at 96 kHz. Two successive samples of a | ||
99 | * channel are stored consecutively in the packet. This quirk is called | ||
100 | * as 'Dual Wire'. | ||
101 | * For this quirk, blocking mode is required and PCM buffer size should | ||
102 | * be aligned to SYT_INTERVAL. | ||
103 | */ | ||
104 | pcm_chs = dice->rx_channels[mode]; | ||
105 | midi_ports = dice->rx_midi_ports[mode]; | ||
106 | if (mode > 1) { | ||
107 | rate /= 2; | ||
108 | pcm_chs *= 2; | ||
109 | dice->rx_stream.double_pcm_frames = true; | ||
110 | } else { | ||
111 | dice->rx_stream.double_pcm_frames = false; | ||
112 | } | ||
114 | 113 | ||
115 | channel = cpu_to_be32((u32)-1); | 114 | amdtp_stream_set_parameters(&dice->rx_stream, rate, |
116 | snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); | 115 | pcm_chs, midi_ports); |
116 | if (mode > 1) { | ||
117 | pcm_chs /= 2; | ||
117 | 118 | ||
118 | fw_iso_resources_free(&dice->rx_resources); | 119 | for (i = 0; i < pcm_chs; i++) { |
120 | dice->rx_stream.pcm_positions[i] = i * 2; | ||
121 | dice->rx_stream.pcm_positions[i + pcm_chs] = i * 2 + 1; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | err = keep_resources(dice, | ||
126 | amdtp_stream_get_max_payload(&dice->rx_stream)); | ||
127 | if (err < 0) { | ||
128 | dev_err(&dice->unit->device, | ||
129 | "fail to keep isochronous resources\n"); | ||
130 | goto end; | ||
131 | } | ||
132 | |||
133 | err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, | ||
134 | fw_parent_device(dice->unit)->max_speed); | ||
135 | if (err < 0) | ||
136 | release_resources(dice); | ||
137 | end: | ||
138 | return err; | ||
139 | } | ||
140 | |||
141 | int snd_dice_stream_start(struct snd_dice *dice, unsigned int rate) | ||
142 | { | ||
143 | unsigned int curr_rate; | ||
144 | int err; | ||
145 | |||
146 | /* Some packet queueing errors. */ | ||
147 | if (amdtp_streaming_error(&dice->rx_stream)) | ||
148 | stop_stream(dice); | ||
149 | |||
150 | /* Stop stream if rate is different. */ | ||
151 | err = snd_dice_transaction_get_rate(dice, &curr_rate); | ||
152 | if (err < 0) { | ||
153 | dev_err(&dice->unit->device, | ||
154 | "fail to get sampling rate\n"); | ||
155 | goto end; | ||
156 | } | ||
157 | if (rate != curr_rate) | ||
158 | stop_stream(dice); | ||
159 | |||
160 | if (!amdtp_stream_running(&dice->rx_stream)) { | ||
161 | snd_dice_transaction_clear_enable(dice); | ||
162 | |||
163 | err = snd_dice_transaction_set_rate(dice, rate); | ||
164 | if (err < 0) { | ||
165 | dev_err(&dice->unit->device, | ||
166 | "fail to set sampling rate\n"); | ||
167 | goto end; | ||
168 | } | ||
169 | |||
170 | /* Start stream. */ | ||
171 | err = start_stream(dice, rate); | ||
172 | if (err < 0) { | ||
173 | dev_err(&dice->unit->device, | ||
174 | "fail to start AMDTP stream\n"); | ||
175 | goto end; | ||
176 | } | ||
177 | err = snd_dice_transaction_set_enable(dice); | ||
178 | if (err < 0) { | ||
179 | dev_err(&dice->unit->device, | ||
180 | "fail to enable interface\n"); | ||
181 | stop_stream(dice); | ||
182 | goto end; | ||
183 | } | ||
184 | |||
185 | if (!amdtp_stream_wait_callback(&dice->rx_stream, | ||
186 | CALLBACK_TIMEOUT)) { | ||
187 | snd_dice_transaction_clear_enable(dice); | ||
188 | stop_stream(dice); | ||
189 | err = -ETIMEDOUT; | ||
190 | } | ||
191 | } | ||
192 | end: | ||
193 | return err; | ||
194 | } | ||
195 | |||
196 | void snd_dice_stream_stop(struct snd_dice *dice) | ||
197 | { | ||
198 | snd_dice_transaction_clear_enable(dice); | ||
199 | stop_stream(dice); | ||
119 | } | 200 | } |
120 | 201 | ||
121 | int snd_dice_stream_init(struct snd_dice *dice) | 202 | int snd_dice_stream_init(struct snd_dice *dice) |
@@ -145,8 +226,8 @@ error: | |||
145 | 226 | ||
146 | void snd_dice_stream_destroy(struct snd_dice *dice) | 227 | void snd_dice_stream_destroy(struct snd_dice *dice) |
147 | { | 228 | { |
148 | amdtp_stream_pcm_abort(&dice->rx_stream); | 229 | snd_dice_transaction_clear_enable(dice); |
149 | snd_dice_stream_stop(dice); | 230 | stop_stream(dice); |
150 | amdtp_stream_destroy(&dice->rx_stream); | 231 | amdtp_stream_destroy(&dice->rx_stream); |
151 | fw_iso_resources_destroy(&dice->rx_resources); | 232 | fw_iso_resources_destroy(&dice->rx_resources); |
152 | } | 233 | } |
@@ -163,8 +244,8 @@ void snd_dice_stream_update(struct snd_dice *dice) | |||
163 | */ | 244 | */ |
164 | dice->global_enabled = false; | 245 | dice->global_enabled = false; |
165 | 246 | ||
166 | amdtp_stream_pcm_abort(&dice->rx_stream); | 247 | stop_stream(dice); |
167 | snd_dice_stream_stop_packets(dice); | 248 | |
168 | fw_iso_resources_update(&dice->rx_resources); | 249 | fw_iso_resources_update(&dice->rx_resources); |
169 | } | 250 | } |
170 | 251 | ||
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 8e2c172de8a7..03a7988871b6 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c | |||
@@ -304,12 +304,8 @@ static void dice_remove(struct fw_unit *unit) | |||
304 | 304 | ||
305 | snd_card_disconnect(dice->card); | 305 | snd_card_disconnect(dice->card); |
306 | 306 | ||
307 | mutex_lock(&dice->mutex); | ||
308 | |||
309 | snd_dice_stream_destroy(dice); | 307 | snd_dice_stream_destroy(dice); |
310 | 308 | ||
311 | mutex_unlock(&dice->mutex); | ||
312 | |||
313 | snd_card_free_when_closed(dice->card); | 309 | snd_card_free_when_closed(dice->card); |
314 | } | 310 | } |
315 | 311 | ||
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 969189a6604f..8be530fe1c34 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h | |||
@@ -160,9 +160,7 @@ extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT]; | |||
160 | int snd_dice_stream_get_rate_mode(struct snd_dice *dice, | 160 | int snd_dice_stream_get_rate_mode(struct snd_dice *dice, |
161 | unsigned int rate, unsigned int *mode); | 161 | unsigned int rate, unsigned int *mode); |
162 | 162 | ||
163 | int snd_dice_stream_start_packets(struct snd_dice *dice); | 163 | int snd_dice_stream_start(struct snd_dice *dice, unsigned int rate); |
164 | int snd_dice_stream_start(struct snd_dice *dice); | ||
165 | void snd_dice_stream_stop_packets(struct snd_dice *dice); | ||
166 | void snd_dice_stream_stop(struct snd_dice *dice); | 164 | void snd_dice_stream_stop(struct snd_dice *dice); |
167 | int snd_dice_stream_init(struct snd_dice *dice); | 165 | int snd_dice_stream_init(struct snd_dice *dice); |
168 | void snd_dice_stream_destroy(struct snd_dice *dice); | 166 | void snd_dice_stream_destroy(struct snd_dice *dice); |