diff options
Diffstat (limited to 'sound/usb/line6/pcm.c')
-rw-r--r-- | sound/usb/line6/pcm.c | 443 |
1 files changed, 272 insertions, 171 deletions
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 8a6059adef69..8461d6bf992f 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c | |||
@@ -45,15 +45,22 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, | |||
45 | { | 45 | { |
46 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | 46 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
47 | int value = ucontrol->value.integer.value[0]; | 47 | int value = ucontrol->value.integer.value[0]; |
48 | int err; | ||
48 | 49 | ||
49 | if (line6pcm->impulse_volume == value) | 50 | if (line6pcm->impulse_volume == value) |
50 | return 0; | 51 | return 0; |
51 | 52 | ||
52 | line6pcm->impulse_volume = value; | 53 | line6pcm->impulse_volume = value; |
53 | if (value > 0) | 54 | if (value > 0) { |
54 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); | 55 | err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); |
55 | else | 56 | if (err < 0) { |
56 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); | 57 | line6pcm->impulse_volume = 0; |
58 | line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); | ||
59 | return err; | ||
60 | } | ||
61 | } else { | ||
62 | line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); | ||
63 | } | ||
57 | return 1; | 64 | return 1; |
58 | } | 65 | } |
59 | 66 | ||
@@ -90,180 +97,277 @@ static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol, | |||
90 | return 1; | 97 | return 1; |
91 | } | 98 | } |
92 | 99 | ||
93 | static bool test_flags(unsigned long flags0, unsigned long flags1, | 100 | /* |
94 | unsigned long mask) | 101 | Unlink all currently active URBs. |
95 | { | 102 | */ |
96 | return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); | 103 | static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm, |
97 | } | 104 | struct line6_pcm_stream *pcms) |
98 | |||
99 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) | ||
100 | { | 105 | { |
101 | unsigned long flags_old, flags_new, flags_final; | 106 | int i; |
102 | int err; | ||
103 | |||
104 | do { | ||
105 | flags_old = ACCESS_ONCE(line6pcm->flags); | ||
106 | flags_new = flags_old | channels; | ||
107 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | ||
108 | |||
109 | flags_final = flags_old; | ||
110 | |||
111 | line6pcm->prev_fbuf = NULL; | ||
112 | |||
113 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { | ||
114 | /* Invoked multiple times in a row so allocate once only */ | ||
115 | if (!line6pcm->buffer_in) { | ||
116 | line6pcm->buffer_in = | ||
117 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | ||
118 | line6pcm->max_packet_size, GFP_KERNEL); | ||
119 | if (!line6pcm->buffer_in) { | ||
120 | err = -ENOMEM; | ||
121 | goto pcm_acquire_error; | ||
122 | } | ||
123 | |||
124 | flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; | ||
125 | } | ||
126 | } | ||
127 | 107 | ||
128 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { | 108 | for (i = 0; i < LINE6_ISO_BUFFERS; i++) { |
129 | /* | 109 | if (test_bit(i, &pcms->active_urbs)) { |
130 | Waiting for completion of active URBs in the stop handler is | 110 | if (!test_and_set_bit(i, &pcms->unlink_urbs)) |
131 | a bug, we therefore report an error if capturing is restarted | 111 | usb_unlink_urb(pcms->urbs[i]); |
132 | too soon. | ||
133 | */ | ||
134 | if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { | ||
135 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | ||
136 | return -EBUSY; | ||
137 | } | 112 | } |
138 | |||
139 | line6pcm->count_in = 0; | ||
140 | line6pcm->prev_fsize = 0; | ||
141 | err = line6_submit_audio_in_all_urbs(line6pcm); | ||
142 | |||
143 | if (err < 0) | ||
144 | goto pcm_acquire_error; | ||
145 | |||
146 | flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; | ||
147 | } | 113 | } |
114 | } | ||
148 | 115 | ||
149 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { | 116 | /* |
150 | /* Invoked multiple times in a row so allocate once only */ | 117 | Wait until unlinking of all currently active URBs has been finished. |
151 | if (!line6pcm->buffer_out) { | 118 | */ |
152 | line6pcm->buffer_out = | 119 | static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, |
153 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | 120 | struct line6_pcm_stream *pcms) |
154 | line6pcm->max_packet_size, GFP_KERNEL); | 121 | { |
155 | if (!line6pcm->buffer_out) { | 122 | int timeout = HZ; |
156 | err = -ENOMEM; | 123 | int i; |
157 | goto pcm_acquire_error; | 124 | int alive; |
158 | } | ||
159 | |||
160 | flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; | ||
161 | } | ||
162 | } | ||
163 | 125 | ||
164 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { | 126 | do { |
165 | /* | 127 | alive = 0; |
166 | See comment above regarding PCM restart. | 128 | for (i = 0; i < LINE6_ISO_BUFFERS; i++) { |
167 | */ | 129 | if (test_bit(i, &pcms->active_urbs)) |
168 | if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { | 130 | alive++; |
169 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | ||
170 | return -EBUSY; | ||
171 | } | 131 | } |
132 | if (!alive) | ||
133 | break; | ||
134 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
135 | schedule_timeout(1); | ||
136 | } while (--timeout > 0); | ||
137 | if (alive) | ||
138 | dev_err(line6pcm->line6->ifcdev, | ||
139 | "timeout: still %d active urbs..\n", alive); | ||
140 | } | ||
172 | 141 | ||
173 | line6pcm->count_out = 0; | 142 | static inline struct line6_pcm_stream * |
174 | err = line6_submit_audio_out_all_urbs(line6pcm); | 143 | get_stream(struct snd_line6_pcm *line6pcm, int direction) |
175 | 144 | { | |
176 | if (err < 0) | 145 | return (direction == SNDRV_PCM_STREAM_PLAYBACK) ? |
177 | goto pcm_acquire_error; | 146 | &line6pcm->out : &line6pcm->in; |
147 | } | ||
178 | 148 | ||
179 | flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; | 149 | /* allocate a buffer if not opened yet; |
150 | * call this in line6pcm.state_change mutex | ||
151 | */ | ||
152 | static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm, | ||
153 | struct line6_pcm_stream *pstr, int type) | ||
154 | { | ||
155 | /* Invoked multiple times in a row so allocate once only */ | ||
156 | if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) { | ||
157 | pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | ||
158 | line6pcm->max_packet_size, GFP_KERNEL); | ||
159 | if (!pstr->buffer) | ||
160 | return -ENOMEM; | ||
180 | } | 161 | } |
181 | |||
182 | return 0; | 162 | return 0; |
183 | |||
184 | pcm_acquire_error: | ||
185 | /* | ||
186 | If not all requested resources/streams could be obtained, release | ||
187 | those which were successfully obtained (if any). | ||
188 | */ | ||
189 | line6_pcm_release(line6pcm, flags_final & channels); | ||
190 | return err; | ||
191 | } | 163 | } |
192 | EXPORT_SYMBOL_GPL(line6_pcm_acquire); | ||
193 | 164 | ||
194 | int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) | 165 | /* free a buffer if all streams are closed; |
166 | * call this in line6pcm.state_change mutex | ||
167 | */ | ||
168 | static void line6_buffer_release(struct snd_line6_pcm *line6pcm, | ||
169 | struct line6_pcm_stream *pstr, int type) | ||
195 | { | 170 | { |
196 | unsigned long flags_old, flags_new; | ||
197 | |||
198 | do { | ||
199 | flags_old = ACCESS_ONCE(line6pcm->flags); | ||
200 | flags_new = flags_old & ~channels; | ||
201 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | ||
202 | 171 | ||
203 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) | 172 | clear_bit(type, &pstr->opened); |
204 | line6_unlink_audio_in_urbs(line6pcm); | 173 | if (!pstr->opened) { |
205 | 174 | line6_wait_clear_audio_urbs(line6pcm, pstr); | |
206 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { | 175 | kfree(pstr->buffer); |
207 | line6_wait_clear_audio_in_urbs(line6pcm); | 176 | pstr->buffer = NULL; |
208 | line6_free_capture_buffer(line6pcm); | ||
209 | } | 177 | } |
178 | } | ||
210 | 179 | ||
211 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) | 180 | /* start a PCM stream */ |
212 | line6_unlink_audio_out_urbs(line6pcm); | 181 | static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, |
182 | int type) | ||
183 | { | ||
184 | unsigned long flags; | ||
185 | struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); | ||
186 | int ret = 0; | ||
187 | |||
188 | spin_lock_irqsave(&pstr->lock, flags); | ||
189 | if (!test_and_set_bit(type, &pstr->running)) { | ||
190 | if (pstr->active_urbs || pstr->unlink_urbs) { | ||
191 | ret = -EBUSY; | ||
192 | goto error; | ||
193 | } | ||
213 | 194 | ||
214 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { | 195 | pstr->count = 0; |
215 | line6_wait_clear_audio_out_urbs(line6pcm); | 196 | /* Submit all currently available URBs */ |
216 | line6_free_playback_buffer(line6pcm); | 197 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) |
198 | ret = line6_submit_audio_out_all_urbs(line6pcm); | ||
199 | else | ||
200 | ret = line6_submit_audio_in_all_urbs(line6pcm); | ||
217 | } | 201 | } |
202 | error: | ||
203 | if (ret < 0) | ||
204 | clear_bit(type, &pstr->running); | ||
205 | spin_unlock_irqrestore(&pstr->lock, flags); | ||
206 | return ret; | ||
207 | } | ||
218 | 208 | ||
219 | return 0; | 209 | /* stop a PCM stream; this doesn't sync with the unlinked URBs */ |
210 | static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, | ||
211 | int type) | ||
212 | { | ||
213 | unsigned long flags; | ||
214 | struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); | ||
215 | |||
216 | spin_lock_irqsave(&pstr->lock, flags); | ||
217 | clear_bit(type, &pstr->running); | ||
218 | if (!pstr->running) { | ||
219 | line6_unlink_audio_urbs(line6pcm, pstr); | ||
220 | if (direction == SNDRV_PCM_STREAM_CAPTURE) { | ||
221 | line6pcm->prev_fbuf = NULL; | ||
222 | line6pcm->prev_fsize = 0; | ||
223 | } | ||
224 | } | ||
225 | spin_unlock_irqrestore(&pstr->lock, flags); | ||
220 | } | 226 | } |
221 | EXPORT_SYMBOL_GPL(line6_pcm_release); | ||
222 | 227 | ||
223 | /* trigger callback */ | 228 | /* common PCM trigger callback */ |
224 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) | 229 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) |
225 | { | 230 | { |
226 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 231 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
227 | struct snd_pcm_substream *s; | 232 | struct snd_pcm_substream *s; |
228 | int err; | 233 | int err; |
229 | 234 | ||
230 | spin_lock(&line6pcm->lock_trigger); | 235 | clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags); |
231 | clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); | ||
232 | 236 | ||
233 | snd_pcm_group_for_each_entry(s, substream) { | 237 | snd_pcm_group_for_each_entry(s, substream) { |
234 | if (s->pcm->card != substream->pcm->card) | 238 | if (s->pcm->card != substream->pcm->card) |
235 | continue; | 239 | continue; |
236 | switch (s->stream) { | ||
237 | case SNDRV_PCM_STREAM_PLAYBACK: | ||
238 | err = snd_line6_playback_trigger(line6pcm, cmd); | ||
239 | 240 | ||
240 | if (err < 0) { | 241 | switch (cmd) { |
241 | spin_unlock(&line6pcm->lock_trigger); | 242 | case SNDRV_PCM_TRIGGER_START: |
243 | case SNDRV_PCM_TRIGGER_RESUME: | ||
244 | err = line6_stream_start(line6pcm, s->stream, | ||
245 | LINE6_STREAM_PCM); | ||
246 | if (err < 0) | ||
242 | return err; | 247 | return err; |
243 | } | ||
244 | |||
245 | break; | 248 | break; |
246 | 249 | ||
247 | case SNDRV_PCM_STREAM_CAPTURE: | 250 | case SNDRV_PCM_TRIGGER_STOP: |
248 | err = snd_line6_capture_trigger(line6pcm, cmd); | 251 | case SNDRV_PCM_TRIGGER_SUSPEND: |
252 | line6_stream_stop(line6pcm, s->stream, | ||
253 | LINE6_STREAM_PCM); | ||
254 | break; | ||
249 | 255 | ||
250 | if (err < 0) { | 256 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
251 | spin_unlock(&line6pcm->lock_trigger); | 257 | if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) |
252 | return err; | 258 | return -EINVAL; |
253 | } | 259 | set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); |
260 | break; | ||
254 | 261 | ||
262 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
263 | if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
264 | return -EINVAL; | ||
265 | clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); | ||
255 | break; | 266 | break; |
256 | 267 | ||
257 | default: | 268 | default: |
258 | dev_err(line6pcm->line6->ifcdev, | 269 | return -EINVAL; |
259 | "Unknown stream direction %d\n", s->stream); | ||
260 | } | 270 | } |
261 | } | 271 | } |
262 | 272 | ||
263 | spin_unlock(&line6pcm->lock_trigger); | ||
264 | return 0; | 273 | return 0; |
265 | } | 274 | } |
266 | 275 | ||
276 | /* common PCM pointer callback */ | ||
277 | snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream) | ||
278 | { | ||
279 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
280 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
281 | |||
282 | return pstr->pos_done; | ||
283 | } | ||
284 | |||
285 | /* Acquire and start duplex streams: | ||
286 | * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR | ||
287 | */ | ||
288 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type) | ||
289 | { | ||
290 | struct line6_pcm_stream *pstr; | ||
291 | int ret = 0, dir; | ||
292 | |||
293 | mutex_lock(&line6pcm->state_mutex); | ||
294 | for (dir = 0; dir < 2; dir++) { | ||
295 | pstr = get_stream(line6pcm, dir); | ||
296 | ret = line6_buffer_acquire(line6pcm, pstr, type); | ||
297 | if (ret < 0) | ||
298 | goto error; | ||
299 | if (!pstr->running) | ||
300 | line6_wait_clear_audio_urbs(line6pcm, pstr); | ||
301 | } | ||
302 | for (dir = 0; dir < 2; dir++) { | ||
303 | ret = line6_stream_start(line6pcm, dir, type); | ||
304 | if (ret < 0) | ||
305 | goto error; | ||
306 | } | ||
307 | error: | ||
308 | mutex_unlock(&line6pcm->state_mutex); | ||
309 | if (ret < 0) | ||
310 | line6_pcm_release(line6pcm, type); | ||
311 | return ret; | ||
312 | } | ||
313 | EXPORT_SYMBOL_GPL(line6_pcm_acquire); | ||
314 | |||
315 | /* Stop and release duplex streams */ | ||
316 | void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) | ||
317 | { | ||
318 | struct line6_pcm_stream *pstr; | ||
319 | int dir; | ||
320 | |||
321 | mutex_lock(&line6pcm->state_mutex); | ||
322 | for (dir = 0; dir < 2; dir++) | ||
323 | line6_stream_stop(line6pcm, dir, type); | ||
324 | for (dir = 0; dir < 2; dir++) { | ||
325 | pstr = get_stream(line6pcm, dir); | ||
326 | line6_buffer_release(line6pcm, pstr, type); | ||
327 | } | ||
328 | mutex_unlock(&line6pcm->state_mutex); | ||
329 | } | ||
330 | EXPORT_SYMBOL_GPL(line6_pcm_release); | ||
331 | |||
332 | /* common PCM hw_params callback */ | ||
333 | int snd_line6_hw_params(struct snd_pcm_substream *substream, | ||
334 | struct snd_pcm_hw_params *hw_params) | ||
335 | { | ||
336 | int ret; | ||
337 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
338 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
339 | |||
340 | mutex_lock(&line6pcm->state_mutex); | ||
341 | ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM); | ||
342 | if (ret < 0) | ||
343 | goto error; | ||
344 | |||
345 | ret = snd_pcm_lib_malloc_pages(substream, | ||
346 | params_buffer_bytes(hw_params)); | ||
347 | if (ret < 0) { | ||
348 | line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); | ||
349 | goto error; | ||
350 | } | ||
351 | |||
352 | pstr->period = params_period_bytes(hw_params); | ||
353 | error: | ||
354 | mutex_unlock(&line6pcm->state_mutex); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | /* common PCM hw_free callback */ | ||
359 | int snd_line6_hw_free(struct snd_pcm_substream *substream) | ||
360 | { | ||
361 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
362 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
363 | |||
364 | mutex_lock(&line6pcm->state_mutex); | ||
365 | line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); | ||
366 | mutex_unlock(&line6pcm->state_mutex); | ||
367 | return snd_pcm_lib_free_pages(substream); | ||
368 | } | ||
369 | |||
370 | |||
267 | /* control info callback */ | 371 | /* control info callback */ |
268 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, | 372 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, |
269 | struct snd_ctl_elem_info *uinfo) | 373 | struct snd_ctl_elem_info *uinfo) |
@@ -282,7 +386,7 @@ static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, | |||
282 | int i; | 386 | int i; |
283 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | 387 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
284 | 388 | ||
285 | for (i = 2; i--;) | 389 | for (i = 0; i < 2; i++) |
286 | ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; | 390 | ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; |
287 | 391 | ||
288 | return 0; | 392 | return 0; |
@@ -295,7 +399,7 @@ static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, | |||
295 | int i, changed = 0; | 399 | int i, changed = 0; |
296 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | 400 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
297 | 401 | ||
298 | for (i = 2; i--;) | 402 | for (i = 0; i < 2; i++) |
299 | if (line6pcm->volume_playback[i] != | 403 | if (line6pcm->volume_playback[i] != |
300 | ucontrol->value.integer.value[i]) { | 404 | ucontrol->value.integer.value[i]) { |
301 | line6pcm->volume_playback[i] = | 405 | line6pcm->volume_playback[i] = |
@@ -334,21 +438,24 @@ static struct snd_kcontrol_new line6_controls[] = { | |||
334 | /* | 438 | /* |
335 | Cleanup the PCM device. | 439 | Cleanup the PCM device. |
336 | */ | 440 | */ |
337 | static void line6_cleanup_pcm(struct snd_pcm *pcm) | 441 | static void cleanup_urbs(struct line6_pcm_stream *pcms) |
338 | { | 442 | { |
339 | int i; | 443 | int i; |
340 | struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); | ||
341 | 444 | ||
342 | for (i = LINE6_ISO_BUFFERS; i--;) { | 445 | for (i = 0; i < LINE6_ISO_BUFFERS; i++) { |
343 | if (line6pcm->urb_audio_out[i]) { | 446 | if (pcms->urbs[i]) { |
344 | usb_kill_urb(line6pcm->urb_audio_out[i]); | 447 | usb_kill_urb(pcms->urbs[i]); |
345 | usb_free_urb(line6pcm->urb_audio_out[i]); | 448 | usb_free_urb(pcms->urbs[i]); |
346 | } | ||
347 | if (line6pcm->urb_audio_in[i]) { | ||
348 | usb_kill_urb(line6pcm->urb_audio_in[i]); | ||
349 | usb_free_urb(line6pcm->urb_audio_in[i]); | ||
350 | } | 449 | } |
351 | } | 450 | } |
451 | } | ||
452 | |||
453 | static void line6_cleanup_pcm(struct snd_pcm *pcm) | ||
454 | { | ||
455 | struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); | ||
456 | |||
457 | cleanup_urbs(&line6pcm->out); | ||
458 | cleanup_urbs(&line6pcm->in); | ||
352 | kfree(line6pcm); | 459 | kfree(line6pcm); |
353 | } | 460 | } |
354 | 461 | ||
@@ -383,8 +490,10 @@ static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) | |||
383 | */ | 490 | */ |
384 | void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) | 491 | void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) |
385 | { | 492 | { |
386 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); | 493 | line6_unlink_audio_urbs(line6pcm, &line6pcm->out); |
387 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); | 494 | line6_unlink_audio_urbs(line6pcm, &line6pcm->in); |
495 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); | ||
496 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); | ||
388 | } | 497 | } |
389 | 498 | ||
390 | /* | 499 | /* |
@@ -411,6 +520,7 @@ int line6_init_pcm(struct usb_line6 *line6, | |||
411 | if (!line6pcm) | 520 | if (!line6pcm) |
412 | return -ENOMEM; | 521 | return -ENOMEM; |
413 | 522 | ||
523 | mutex_init(&line6pcm->state_mutex); | ||
414 | line6pcm->pcm = pcm; | 524 | line6pcm->pcm = pcm; |
415 | line6pcm->properties = properties; | 525 | line6pcm->properties = properties; |
416 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; | 526 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; |
@@ -424,9 +534,8 @@ int line6_init_pcm(struct usb_line6 *line6, | |||
424 | usb_maxpacket(line6->usbdev, | 534 | usb_maxpacket(line6->usbdev, |
425 | usb_sndisocpipe(line6->usbdev, ep_write), 1)); | 535 | usb_sndisocpipe(line6->usbdev, ep_write), 1)); |
426 | 536 | ||
427 | spin_lock_init(&line6pcm->lock_audio_out); | 537 | spin_lock_init(&line6pcm->out.lock); |
428 | spin_lock_init(&line6pcm->lock_audio_in); | 538 | spin_lock_init(&line6pcm->in.lock); |
429 | spin_lock_init(&line6pcm->lock_trigger); | ||
430 | line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; | 539 | line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; |
431 | 540 | ||
432 | line6->line6pcm = line6pcm; | 541 | line6->line6pcm = line6pcm; |
@@ -458,30 +567,22 @@ EXPORT_SYMBOL_GPL(line6_init_pcm); | |||
458 | int snd_line6_prepare(struct snd_pcm_substream *substream) | 567 | int snd_line6_prepare(struct snd_pcm_substream *substream) |
459 | { | 568 | { |
460 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 569 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
461 | 570 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | |
462 | switch (substream->stream) { | 571 | |
463 | case SNDRV_PCM_STREAM_PLAYBACK: | 572 | mutex_lock(&line6pcm->state_mutex); |
464 | if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) | 573 | if (!pstr->running) |
465 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); | 574 | line6_wait_clear_audio_urbs(line6pcm, pstr); |
466 | 575 | ||
467 | break; | 576 | if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) { |
468 | 577 | line6pcm->out.count = 0; | |
469 | case SNDRV_PCM_STREAM_CAPTURE: | 578 | line6pcm->out.pos = 0; |
470 | if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) | 579 | line6pcm->out.pos_done = 0; |
471 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); | 580 | line6pcm->out.bytes = 0; |
472 | 581 | line6pcm->in.count = 0; | |
473 | break; | 582 | line6pcm->in.pos_done = 0; |
474 | } | 583 | line6pcm->in.bytes = 0; |
475 | |||
476 | if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { | ||
477 | line6pcm->count_out = 0; | ||
478 | line6pcm->pos_out = 0; | ||
479 | line6pcm->pos_out_done = 0; | ||
480 | line6pcm->bytes_out = 0; | ||
481 | line6pcm->count_in = 0; | ||
482 | line6pcm->pos_in_done = 0; | ||
483 | line6pcm->bytes_in = 0; | ||
484 | } | 584 | } |
485 | 585 | ||
586 | mutex_unlock(&line6pcm->state_mutex); | ||
486 | return 0; | 587 | return 0; |
487 | } | 588 | } |