diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 8 | ||||
-rw-r--r-- | sound/usb/card.h | 4 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 40 | ||||
-rw-r--r-- | sound/usb/endpoint.h | 3 | ||||
-rw-r--r-- | sound/usb/pcm.c | 418 | ||||
-rw-r--r-- | sound/usb/stream.c | 31 |
6 files changed, 385 insertions, 119 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 6bc88b7ce4f..d5b5c3388e2 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -131,8 +131,9 @@ static void snd_usb_stream_disconnect(struct list_head *head) | |||
131 | subs = &as->substream[idx]; | 131 | subs = &as->substream[idx]; |
132 | if (!subs->num_formats) | 132 | if (!subs->num_formats) |
133 | continue; | 133 | continue; |
134 | snd_usb_release_substream_urbs(subs, 1); | ||
135 | subs->interface = -1; | 134 | subs->interface = -1; |
135 | subs->data_endpoint = NULL; | ||
136 | subs->sync_endpoint = NULL; | ||
136 | } | 137 | } |
137 | } | 138 | } |
138 | 139 | ||
@@ -350,6 +351,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
350 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | 351 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), |
351 | le16_to_cpu(dev->descriptor.idProduct)); | 352 | le16_to_cpu(dev->descriptor.idProduct)); |
352 | INIT_LIST_HEAD(&chip->pcm_list); | 353 | INIT_LIST_HEAD(&chip->pcm_list); |
354 | INIT_LIST_HEAD(&chip->ep_list); | ||
353 | INIT_LIST_HEAD(&chip->midi_list); | 355 | INIT_LIST_HEAD(&chip->midi_list); |
354 | INIT_LIST_HEAD(&chip->mixer_list); | 356 | INIT_LIST_HEAD(&chip->mixer_list); |
355 | 357 | ||
@@ -567,6 +569,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
567 | list_for_each(p, &chip->pcm_list) { | 569 | list_for_each(p, &chip->pcm_list) { |
568 | snd_usb_stream_disconnect(p); | 570 | snd_usb_stream_disconnect(p); |
569 | } | 571 | } |
572 | /* release the endpoint resources */ | ||
573 | list_for_each(p, &chip->ep_list) { | ||
574 | snd_usb_endpoint_free(p); | ||
575 | } | ||
570 | /* release the midi resources */ | 576 | /* release the midi resources */ |
571 | list_for_each(p, &chip->midi_list) { | 577 | list_for_each(p, &chip->midi_list) { |
572 | snd_usbmidi_disconnect(p); | 578 | snd_usbmidi_disconnect(p); |
diff --git a/sound/usb/card.h b/sound/usb/card.h index 9acbd4a1228..8a08687e5bc 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h | |||
@@ -145,6 +145,10 @@ struct snd_usb_substream { | |||
145 | struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */ | 145 | struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */ |
146 | char *syncbuf; /* sync buffer for all sync URBs */ | 146 | char *syncbuf; /* sync buffer for all sync URBs */ |
147 | dma_addr_t sync_dma; /* DMA address of syncbuf */ | 147 | dma_addr_t sync_dma; /* DMA address of syncbuf */ |
148 | /* data and sync endpoints for this stream */ | ||
149 | struct snd_usb_endpoint *data_endpoint; | ||
150 | struct snd_usb_endpoint *sync_endpoint; | ||
151 | unsigned long flags; | ||
148 | 152 | ||
149 | u64 formats; /* format bitmasks (all or'ed) */ | 153 | u64 formats; /* format bitmasks (all or'ed) */ |
150 | unsigned int num_formats; /* number of supported audio formats (list) */ | 154 | unsigned int num_formats; /* number of supported audio formats (list) */ |
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index ea25265427a..1b0ed22cff7 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -912,46 +912,6 @@ void snd_usb_init_substream(struct snd_usb_stream *as, | |||
912 | subs->fmt_type = fp->fmt_type; | 912 | subs->fmt_type = fp->fmt_type; |
913 | } | 913 | } |
914 | 914 | ||
915 | int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
916 | { | ||
917 | struct snd_usb_substream *subs = substream->runtime->private_data; | ||
918 | |||
919 | switch (cmd) { | ||
920 | case SNDRV_PCM_TRIGGER_START: | ||
921 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
922 | subs->ops.prepare = prepare_playback_urb; | ||
923 | return 0; | ||
924 | case SNDRV_PCM_TRIGGER_STOP: | ||
925 | return deactivate_urbs_old(subs, 0, 0); | ||
926 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
927 | subs->ops.prepare = prepare_nodata_playback_urb; | ||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | return -EINVAL; | ||
932 | } | ||
933 | |||
934 | int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
935 | { | ||
936 | struct snd_usb_substream *subs = substream->runtime->private_data; | ||
937 | |||
938 | switch (cmd) { | ||
939 | case SNDRV_PCM_TRIGGER_START: | ||
940 | subs->ops.retire = retire_capture_urb; | ||
941 | return start_urbs(subs, substream->runtime); | ||
942 | case SNDRV_PCM_TRIGGER_STOP: | ||
943 | return deactivate_urbs_old(subs, 0, 0); | ||
944 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
945 | subs->ops.retire = retire_paused_capture_urb; | ||
946 | return 0; | ||
947 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
948 | subs->ops.retire = retire_capture_urb; | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | return -EINVAL; | ||
953 | } | ||
954 | |||
955 | int snd_usb_substream_prepare(struct snd_usb_substream *subs, | 915 | int snd_usb_substream_prepare(struct snd_usb_substream *subs, |
956 | struct snd_pcm_runtime *runtime) | 916 | struct snd_pcm_runtime *runtime) |
957 | { | 917 | { |
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 9f083d7d6cf..e540768de3d 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h | |||
@@ -15,9 +15,6 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force); | |||
15 | int snd_usb_substream_prepare(struct snd_usb_substream *subs, | 15 | int snd_usb_substream_prepare(struct snd_usb_substream *subs, |
16 | struct snd_pcm_runtime *runtime); | 16 | struct snd_pcm_runtime *runtime); |
17 | 17 | ||
18 | int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd); | ||
19 | int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd); | ||
20 | |||
21 | 18 | ||
22 | #define SND_USB_ENDPOINT_TYPE_DATA 0 | 19 | #define SND_USB_ENDPOINT_TYPE_DATA 0 |
23 | #define SND_USB_ENDPOINT_TYPE_SYNC 1 | 20 | #define SND_USB_ENDPOINT_TYPE_SYNC 1 |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0eed6115c2d..0f107834c10 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/ratelimit.h> | ||
19 | #include <linux/usb.h> | 20 | #include <linux/usb.h> |
20 | #include <linux/usb/audio.h> | 21 | #include <linux/usb/audio.h> |
21 | #include <linux/usb/audio-v2.h> | 22 | #include <linux/usb/audio-v2.h> |
@@ -34,6 +35,9 @@ | |||
34 | #include "clock.h" | 35 | #include "clock.h" |
35 | #include "power.h" | 36 | #include "power.h" |
36 | 37 | ||
38 | #define SUBSTREAM_FLAG_DATA_EP_STARTED 0 | ||
39 | #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 | ||
40 | |||
37 | /* return the estimated delay based on USB frame counters */ | 41 | /* return the estimated delay based on USB frame counters */ |
38 | snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, | 42 | snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, |
39 | unsigned int rate) | 43 | unsigned int rate) |
@@ -208,6 +212,84 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | |||
208 | } | 212 | } |
209 | } | 213 | } |
210 | 214 | ||
215 | static int start_endpoints(struct snd_usb_substream *subs) | ||
216 | { | ||
217 | int err; | ||
218 | |||
219 | if (!subs->data_endpoint) | ||
220 | return -EINVAL; | ||
221 | |||
222 | if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { | ||
223 | struct snd_usb_endpoint *ep = subs->data_endpoint; | ||
224 | |||
225 | snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep); | ||
226 | |||
227 | ep->data_subs = subs; | ||
228 | err = snd_usb_endpoint_start(ep); | ||
229 | if (err < 0) { | ||
230 | clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); | ||
231 | return err; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (subs->sync_endpoint && | ||
236 | !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { | ||
237 | struct snd_usb_endpoint *ep = subs->sync_endpoint; | ||
238 | |||
239 | snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep); | ||
240 | |||
241 | ep->sync_slave = subs->data_endpoint; | ||
242 | err = snd_usb_endpoint_start(ep); | ||
243 | if (err < 0) { | ||
244 | clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); | ||
245 | return err; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static void stop_endpoints(struct snd_usb_substream *subs, | ||
253 | int force, int can_sleep, int wait) | ||
254 | { | ||
255 | if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) | ||
256 | snd_usb_endpoint_stop(subs->sync_endpoint, | ||
257 | force, can_sleep, wait); | ||
258 | |||
259 | if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) | ||
260 | snd_usb_endpoint_stop(subs->data_endpoint, | ||
261 | force, can_sleep, wait); | ||
262 | } | ||
263 | |||
264 | static int activate_endpoints(struct snd_usb_substream *subs) | ||
265 | { | ||
266 | if (subs->sync_endpoint) { | ||
267 | int ret; | ||
268 | |||
269 | ret = snd_usb_endpoint_activate(subs->sync_endpoint); | ||
270 | if (ret < 0) | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | return snd_usb_endpoint_activate(subs->data_endpoint); | ||
275 | } | ||
276 | |||
277 | static int deactivate_endpoints(struct snd_usb_substream *subs) | ||
278 | { | ||
279 | int reta, retb; | ||
280 | |||
281 | reta = snd_usb_endpoint_deactivate(subs->sync_endpoint); | ||
282 | retb = snd_usb_endpoint_deactivate(subs->data_endpoint); | ||
283 | |||
284 | if (reta < 0) | ||
285 | return reta; | ||
286 | |||
287 | if (retb < 0) | ||
288 | return retb; | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
211 | /* | 293 | /* |
212 | * find a matching format and set up the interface | 294 | * find a matching format and set up the interface |
213 | */ | 295 | */ |
@@ -232,40 +314,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
232 | if (fmt == subs->cur_audiofmt) | 314 | if (fmt == subs->cur_audiofmt) |
233 | return 0; | 315 | return 0; |
234 | 316 | ||
235 | /* close the old interface */ | 317 | subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, |
236 | if (subs->interface >= 0 && subs->interface != fmt->iface) { | 318 | alts, fmt->endpoint, subs->direction, |
237 | if (usb_set_interface(subs->dev, subs->interface, 0) < 0) { | 319 | SND_USB_ENDPOINT_TYPE_DATA); |
238 | snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n", | 320 | if (!subs->data_endpoint) |
239 | dev->devnum, fmt->iface, fmt->altsetting); | 321 | return -EINVAL; |
240 | return -EIO; | ||
241 | } | ||
242 | subs->interface = -1; | ||
243 | subs->altset_idx = 0; | ||
244 | } | ||
245 | |||
246 | /* set interface */ | ||
247 | if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) { | ||
248 | if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) { | ||
249 | snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n", | ||
250 | dev->devnum, fmt->iface, fmt->altsetting); | ||
251 | return -EIO; | ||
252 | } | ||
253 | snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting); | ||
254 | subs->interface = fmt->iface; | ||
255 | subs->altset_idx = fmt->altset_idx; | ||
256 | } | ||
257 | |||
258 | /* create a data pipe */ | ||
259 | ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK; | ||
260 | if (is_playback) | ||
261 | subs->datapipe = usb_sndisocpipe(dev, ep); | ||
262 | else | ||
263 | subs->datapipe = usb_rcvisocpipe(dev, ep); | ||
264 | subs->datainterval = fmt->datainterval; | ||
265 | subs->syncpipe = subs->syncinterval = 0; | ||
266 | subs->maxpacksize = fmt->maxpacksize; | ||
267 | subs->syncmaxsize = 0; | ||
268 | subs->fill_max = 0; | ||
269 | 322 | ||
270 | /* we need a sync pipe in async OUT or adaptive IN mode */ | 323 | /* we need a sync pipe in async OUT or adaptive IN mode */ |
271 | /* check the number of EP, since some devices have broken | 324 | /* check the number of EP, since some devices have broken |
@@ -276,6 +329,15 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
276 | if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || | 329 | if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || |
277 | (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && | 330 | (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && |
278 | altsd->bNumEndpoints >= 2) { | 331 | altsd->bNumEndpoints >= 2) { |
332 | switch (subs->stream->chip->usb_id) { | ||
333 | case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ | ||
334 | case USB_ID(0x0763, 0x2081): | ||
335 | ep = 0x81; | ||
336 | iface = usb_ifnum_to_if(dev, 2); | ||
337 | alts = &iface->altsetting[1]; | ||
338 | goto add_sync_ep; | ||
339 | } | ||
340 | |||
279 | /* check sync-pipe endpoint */ | 341 | /* check sync-pipe endpoint */ |
280 | /* ... and check descriptor size before accessing bSynchAddress | 342 | /* ... and check descriptor size before accessing bSynchAddress |
281 | because there is a version of the SB Audigy 2 NX firmware lacking | 343 | because there is a version of the SB Audigy 2 NX firmware lacking |
@@ -295,28 +357,16 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
295 | dev->devnum, fmt->iface, fmt->altsetting); | 357 | dev->devnum, fmt->iface, fmt->altsetting); |
296 | return -EINVAL; | 358 | return -EINVAL; |
297 | } | 359 | } |
298 | ep &= USB_ENDPOINT_NUMBER_MASK; | 360 | add_sync_ep: |
299 | if (is_playback) | 361 | subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, |
300 | subs->syncpipe = usb_rcvisocpipe(dev, ep); | 362 | alts, ep, !subs->direction, |
301 | else | 363 | SND_USB_ENDPOINT_TYPE_SYNC); |
302 | subs->syncpipe = usb_sndisocpipe(dev, ep); | 364 | |
303 | if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | 365 | if (!subs->sync_endpoint) |
304 | get_endpoint(alts, 1)->bRefresh >= 1 && | 366 | return -EINVAL; |
305 | get_endpoint(alts, 1)->bRefresh <= 9) | 367 | |
306 | subs->syncinterval = get_endpoint(alts, 1)->bRefresh; | 368 | subs->data_endpoint->sync_master = subs->sync_endpoint; |
307 | else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 369 | } |
308 | subs->syncinterval = 1; | ||
309 | else if (get_endpoint(alts, 1)->bInterval >= 1 && | ||
310 | get_endpoint(alts, 1)->bInterval <= 16) | ||
311 | subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; | ||
312 | else | ||
313 | subs->syncinterval = 3; | ||
314 | subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); | ||
315 | } | ||
316 | |||
317 | /* always fill max packet size */ | ||
318 | if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX) | ||
319 | subs->fill_max = 1; | ||
320 | 370 | ||
321 | if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0) | 371 | if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0) |
322 | return err; | 372 | return err; |
@@ -390,12 +440,22 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
390 | if (changed) { | 440 | if (changed) { |
391 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 441 | mutex_lock(&subs->stream->chip->shutdown_mutex); |
392 | /* format changed */ | 442 | /* format changed */ |
393 | snd_usb_release_substream_urbs(subs, 0); | 443 | stop_endpoints(subs, 0, 0, 0); |
394 | /* influenced: period_bytes, channels, rate, format, */ | 444 | deactivate_endpoints(subs); |
395 | ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params), | 445 | |
396 | params_rate(hw_params), | 446 | ret = activate_endpoints(subs); |
397 | snd_pcm_format_physical_width(params_format(hw_params)) * | 447 | if (ret < 0) |
398 | params_channels(hw_params)); | 448 | goto unlock; |
449 | |||
450 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt, | ||
451 | subs->sync_endpoint); | ||
452 | if (ret < 0) | ||
453 | goto unlock; | ||
454 | |||
455 | if (subs->sync_endpoint) | ||
456 | ret = snd_usb_endpoint_set_params(subs->sync_endpoint, | ||
457 | hw_params, fmt, NULL); | ||
458 | unlock: | ||
399 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 459 | mutex_unlock(&subs->stream->chip->shutdown_mutex); |
400 | } | 460 | } |
401 | 461 | ||
@@ -415,7 +475,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
415 | subs->cur_rate = 0; | 475 | subs->cur_rate = 0; |
416 | subs->period_bytes = 0; | 476 | subs->period_bytes = 0; |
417 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 477 | mutex_lock(&subs->stream->chip->shutdown_mutex); |
418 | snd_usb_release_substream_urbs(subs, 0); | 478 | stop_endpoints(subs, 0, 1, 1); |
419 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 479 | mutex_unlock(&subs->stream->chip->shutdown_mutex); |
420 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 480 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
421 | } | 481 | } |
@@ -435,19 +495,28 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
435 | return -ENXIO; | 495 | return -ENXIO; |
436 | } | 496 | } |
437 | 497 | ||
498 | if (snd_BUG_ON(!subs->data_endpoint)) | ||
499 | return -EIO; | ||
500 | |||
438 | /* some unit conversions in runtime */ | 501 | /* some unit conversions in runtime */ |
439 | subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); | 502 | subs->data_endpoint->maxframesize = |
440 | subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); | 503 | bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); |
504 | subs->data_endpoint->curframesize = | ||
505 | bytes_to_frames(runtime, subs->data_endpoint->curpacksize); | ||
441 | 506 | ||
442 | /* reset the pointer */ | 507 | /* reset the pointer */ |
443 | subs->hwptr_done = 0; | 508 | subs->hwptr_done = 0; |
444 | subs->transfer_done = 0; | 509 | subs->transfer_done = 0; |
445 | subs->phase = 0; | ||
446 | subs->last_delay = 0; | 510 | subs->last_delay = 0; |
447 | subs->last_frame_number = 0; | 511 | subs->last_frame_number = 0; |
448 | runtime->delay = 0; | 512 | runtime->delay = 0; |
449 | 513 | ||
450 | return snd_usb_substream_prepare(subs, runtime); | 514 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
515 | * updates for all URBs would happen at the same time when starting */ | ||
516 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) | ||
517 | return start_endpoints(subs); | ||
518 | |||
519 | return 0; | ||
451 | } | 520 | } |
452 | 521 | ||
453 | static struct snd_pcm_hardware snd_usb_hardware = | 522 | static struct snd_pcm_hardware snd_usb_hardware = |
@@ -842,16 +911,171 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | |||
842 | 911 | ||
843 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | 912 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) |
844 | { | 913 | { |
914 | int ret; | ||
845 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); | 915 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); |
846 | struct snd_usb_substream *subs = &as->substream[direction]; | 916 | struct snd_usb_substream *subs = &as->substream[direction]; |
847 | 917 | ||
848 | if (!as->chip->shutdown && subs->interface >= 0) { | 918 | stop_endpoints(subs, 0, 0, 0); |
849 | usb_set_interface(subs->dev, subs->interface, 0); | 919 | ret = deactivate_endpoints(subs); |
850 | subs->interface = -1; | ||
851 | } | ||
852 | subs->pcm_substream = NULL; | 920 | subs->pcm_substream = NULL; |
853 | snd_usb_autosuspend(subs->stream->chip); | 921 | snd_usb_autosuspend(subs->stream->chip); |
854 | return 0; | 922 | |
923 | return ret; | ||
924 | } | ||
925 | |||
926 | /* Since a URB can handle only a single linear buffer, we must use double | ||
927 | * buffering when the data to be transferred overflows the buffer boundary. | ||
928 | * To avoid inconsistencies when updating hwptr_done, we use double buffering | ||
929 | * for all URBs. | ||
930 | */ | ||
931 | static void retire_capture_urb(struct snd_usb_substream *subs, | ||
932 | struct urb *urb) | ||
933 | { | ||
934 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; | ||
935 | unsigned int stride, frames, bytes, oldptr; | ||
936 | int i, period_elapsed = 0; | ||
937 | unsigned long flags; | ||
938 | unsigned char *cp; | ||
939 | |||
940 | stride = runtime->frame_bits >> 3; | ||
941 | |||
942 | for (i = 0; i < urb->number_of_packets; i++) { | ||
943 | cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
944 | if (urb->iso_frame_desc[i].status && printk_ratelimit()) { | ||
945 | snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); | ||
946 | // continue; | ||
947 | } | ||
948 | bytes = urb->iso_frame_desc[i].actual_length; | ||
949 | frames = bytes / stride; | ||
950 | if (!subs->txfr_quirk) | ||
951 | bytes = frames * stride; | ||
952 | if (bytes % (runtime->sample_bits >> 3) != 0) { | ||
953 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
954 | int oldbytes = bytes; | ||
955 | #endif | ||
956 | bytes = frames * stride; | ||
957 | snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", | ||
958 | oldbytes, bytes); | ||
959 | } | ||
960 | /* update the current pointer */ | ||
961 | spin_lock_irqsave(&subs->lock, flags); | ||
962 | oldptr = subs->hwptr_done; | ||
963 | subs->hwptr_done += bytes; | ||
964 | if (subs->hwptr_done >= runtime->buffer_size * stride) | ||
965 | subs->hwptr_done -= runtime->buffer_size * stride; | ||
966 | frames = (bytes + (oldptr % stride)) / stride; | ||
967 | subs->transfer_done += frames; | ||
968 | if (subs->transfer_done >= runtime->period_size) { | ||
969 | subs->transfer_done -= runtime->period_size; | ||
970 | period_elapsed = 1; | ||
971 | } | ||
972 | spin_unlock_irqrestore(&subs->lock, flags); | ||
973 | /* copy a data chunk */ | ||
974 | if (oldptr + bytes > runtime->buffer_size * stride) { | ||
975 | unsigned int bytes1 = | ||
976 | runtime->buffer_size * stride - oldptr; | ||
977 | memcpy(runtime->dma_area + oldptr, cp, bytes1); | ||
978 | memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); | ||
979 | } else { | ||
980 | memcpy(runtime->dma_area + oldptr, cp, bytes); | ||
981 | } | ||
982 | } | ||
983 | |||
984 | if (period_elapsed) | ||
985 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
986 | } | ||
987 | |||
988 | static void prepare_playback_urb(struct snd_usb_substream *subs, | ||
989 | struct urb *urb) | ||
990 | { | ||
991 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; | ||
992 | struct snd_urb_ctx *ctx = urb->context; | ||
993 | unsigned int counts, frames, bytes; | ||
994 | int i, stride, period_elapsed = 0; | ||
995 | unsigned long flags; | ||
996 | |||
997 | stride = runtime->frame_bits >> 3; | ||
998 | |||
999 | frames = 0; | ||
1000 | urb->number_of_packets = 0; | ||
1001 | spin_lock_irqsave(&subs->lock, flags); | ||
1002 | for (i = 0; i < ctx->packets; i++) { | ||
1003 | counts = ctx->packet_size[i]; | ||
1004 | /* set up descriptor */ | ||
1005 | urb->iso_frame_desc[i].offset = frames * stride; | ||
1006 | urb->iso_frame_desc[i].length = counts * stride; | ||
1007 | frames += counts; | ||
1008 | urb->number_of_packets++; | ||
1009 | subs->transfer_done += counts; | ||
1010 | if (subs->transfer_done >= runtime->period_size) { | ||
1011 | subs->transfer_done -= runtime->period_size; | ||
1012 | period_elapsed = 1; | ||
1013 | if (subs->fmt_type == UAC_FORMAT_TYPE_II) { | ||
1014 | if (subs->transfer_done > 0) { | ||
1015 | /* FIXME: fill-max mode is not | ||
1016 | * supported yet */ | ||
1017 | frames -= subs->transfer_done; | ||
1018 | counts -= subs->transfer_done; | ||
1019 | urb->iso_frame_desc[i].length = | ||
1020 | counts * stride; | ||
1021 | subs->transfer_done = 0; | ||
1022 | } | ||
1023 | i++; | ||
1024 | if (i < ctx->packets) { | ||
1025 | /* add a transfer delimiter */ | ||
1026 | urb->iso_frame_desc[i].offset = | ||
1027 | frames * stride; | ||
1028 | urb->iso_frame_desc[i].length = 0; | ||
1029 | urb->number_of_packets++; | ||
1030 | } | ||
1031 | break; | ||
1032 | } | ||
1033 | } | ||
1034 | if (period_elapsed && | ||
1035 | !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */ | ||
1036 | break; | ||
1037 | } | ||
1038 | bytes = frames * stride; | ||
1039 | if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { | ||
1040 | /* err, the transferred area goes over buffer boundary. */ | ||
1041 | unsigned int bytes1 = | ||
1042 | runtime->buffer_size * stride - subs->hwptr_done; | ||
1043 | memcpy(urb->transfer_buffer, | ||
1044 | runtime->dma_area + subs->hwptr_done, bytes1); | ||
1045 | memcpy(urb->transfer_buffer + bytes1, | ||
1046 | runtime->dma_area, bytes - bytes1); | ||
1047 | } else { | ||
1048 | memcpy(urb->transfer_buffer, | ||
1049 | runtime->dma_area + subs->hwptr_done, bytes); | ||
1050 | } | ||
1051 | subs->hwptr_done += bytes; | ||
1052 | if (subs->hwptr_done >= runtime->buffer_size * stride) | ||
1053 | subs->hwptr_done -= runtime->buffer_size * stride; | ||
1054 | runtime->delay += frames; | ||
1055 | spin_unlock_irqrestore(&subs->lock, flags); | ||
1056 | urb->transfer_buffer_length = bytes; | ||
1057 | if (period_elapsed) | ||
1058 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
1059 | } | ||
1060 | |||
1061 | /* | ||
1062 | * process after playback data complete | ||
1063 | * - decrease the delay count again | ||
1064 | */ | ||
1065 | static void retire_playback_urb(struct snd_usb_substream *subs, | ||
1066 | struct urb *urb) | ||
1067 | { | ||
1068 | unsigned long flags; | ||
1069 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; | ||
1070 | int stride = runtime->frame_bits >> 3; | ||
1071 | int processed = urb->transfer_buffer_length / stride; | ||
1072 | |||
1073 | spin_lock_irqsave(&subs->lock, flags); | ||
1074 | if (processed > runtime->delay) | ||
1075 | runtime->delay = 0; | ||
1076 | else | ||
1077 | runtime->delay -= processed; | ||
1078 | spin_unlock_irqrestore(&subs->lock, flags); | ||
855 | } | 1079 | } |
856 | 1080 | ||
857 | static int snd_usb_playback_open(struct snd_pcm_substream *substream) | 1081 | static int snd_usb_playback_open(struct snd_pcm_substream *substream) |
@@ -874,6 +1098,56 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream) | |||
874 | return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); | 1098 | return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); |
875 | } | 1099 | } |
876 | 1100 | ||
1101 | static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, | ||
1102 | int cmd) | ||
1103 | { | ||
1104 | struct snd_usb_substream *subs = substream->runtime->private_data; | ||
1105 | |||
1106 | switch (cmd) { | ||
1107 | case SNDRV_PCM_TRIGGER_START: | ||
1108 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1109 | subs->data_endpoint->prepare_data_urb = prepare_playback_urb; | ||
1110 | subs->data_endpoint->retire_data_urb = retire_playback_urb; | ||
1111 | return 0; | ||
1112 | case SNDRV_PCM_TRIGGER_STOP: | ||
1113 | stop_endpoints(subs, 0, 0, 0); | ||
1114 | return 0; | ||
1115 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1116 | subs->data_endpoint->prepare_data_urb = NULL; | ||
1117 | subs->data_endpoint->retire_data_urb = NULL; | ||
1118 | return 0; | ||
1119 | } | ||
1120 | |||
1121 | return -EINVAL; | ||
1122 | } | ||
1123 | |||
1124 | int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1125 | { | ||
1126 | int err; | ||
1127 | struct snd_usb_substream *subs = substream->runtime->private_data; | ||
1128 | |||
1129 | switch (cmd) { | ||
1130 | case SNDRV_PCM_TRIGGER_START: | ||
1131 | err = start_endpoints(subs); | ||
1132 | if (err < 0) | ||
1133 | return err; | ||
1134 | |||
1135 | subs->data_endpoint->retire_data_urb = retire_capture_urb; | ||
1136 | return 0; | ||
1137 | case SNDRV_PCM_TRIGGER_STOP: | ||
1138 | stop_endpoints(subs, 0, 0, 0); | ||
1139 | return 0; | ||
1140 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1141 | subs->data_endpoint->retire_data_urb = NULL; | ||
1142 | return 0; | ||
1143 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1144 | subs->data_endpoint->retire_data_urb = retire_capture_urb; | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | return -EINVAL; | ||
1149 | } | ||
1150 | |||
877 | static struct snd_pcm_ops snd_usb_playback_ops = { | 1151 | static struct snd_pcm_ops snd_usb_playback_ops = { |
878 | .open = snd_usb_playback_open, | 1152 | .open = snd_usb_playback_open, |
879 | .close = snd_usb_playback_close, | 1153 | .close = snd_usb_playback_close, |
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 5ff8010b2d6..6b7d7a2b7ba 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c | |||
@@ -73,6 +73,31 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) | |||
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
76 | /* | ||
77 | * initialize the substream instance. | ||
78 | */ | ||
79 | |||
80 | static void snd_usb_init_substream(struct snd_usb_stream *as, | ||
81 | int stream, | ||
82 | struct audioformat *fp) | ||
83 | { | ||
84 | struct snd_usb_substream *subs = &as->substream[stream]; | ||
85 | |||
86 | INIT_LIST_HEAD(&subs->fmt_list); | ||
87 | spin_lock_init(&subs->lock); | ||
88 | |||
89 | subs->stream = as; | ||
90 | subs->direction = stream; | ||
91 | subs->dev = as->chip->dev; | ||
92 | subs->txfr_quirk = as->chip->txfr_quirk; | ||
93 | |||
94 | snd_usb_set_pcm_ops(as->pcm, stream); | ||
95 | |||
96 | list_add_tail(&fp->list, &subs->fmt_list); | ||
97 | subs->formats |= fp->formats; | ||
98 | subs->num_formats++; | ||
99 | subs->fmt_type = fp->fmt_type; | ||
100 | } | ||
76 | 101 | ||
77 | /* | 102 | /* |
78 | * add this endpoint to the chip instance. | 103 | * add this endpoint to the chip instance. |
@@ -94,9 +119,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | |||
94 | if (as->fmt_type != fp->fmt_type) | 119 | if (as->fmt_type != fp->fmt_type) |
95 | continue; | 120 | continue; |
96 | subs = &as->substream[stream]; | 121 | subs = &as->substream[stream]; |
97 | if (!subs->endpoint) | 122 | if (!subs->data_endpoint) |
98 | continue; | 123 | continue; |
99 | if (subs->endpoint == fp->endpoint) { | 124 | if (subs->data_endpoint->ep_num == fp->endpoint) { |
100 | list_add_tail(&fp->list, &subs->fmt_list); | 125 | list_add_tail(&fp->list, &subs->fmt_list); |
101 | subs->num_formats++; | 126 | subs->num_formats++; |
102 | subs->formats |= fp->formats; | 127 | subs->formats |= fp->formats; |
@@ -109,7 +134,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | |||
109 | if (as->fmt_type != fp->fmt_type) | 134 | if (as->fmt_type != fp->fmt_type) |
110 | continue; | 135 | continue; |
111 | subs = &as->substream[stream]; | 136 | subs = &as->substream[stream]; |
112 | if (subs->endpoint) | 137 | if (subs->data_endpoint) |
113 | continue; | 138 | continue; |
114 | err = snd_pcm_new_stream(as->pcm, stream, 1); | 139 | err = snd_pcm_new_stream(as->pcm, stream, 1); |
115 | if (err < 0) | 140 | if (err < 0) |