diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 4 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 24 | ||||
-rw-r--r-- | sound/usb/endpoint.h | 3 | ||||
-rw-r--r-- | sound/usb/pcm.c | 64 |
4 files changed, 66 insertions, 29 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index d5b5c3388e28..4a469f0cb6d4 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -553,7 +553,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
553 | struct snd_usb_audio *chip) | 553 | struct snd_usb_audio *chip) |
554 | { | 554 | { |
555 | struct snd_card *card; | 555 | struct snd_card *card; |
556 | struct list_head *p; | 556 | struct list_head *p, *n; |
557 | 557 | ||
558 | if (chip == (void *)-1L) | 558 | if (chip == (void *)-1L) |
559 | return; | 559 | return; |
@@ -570,7 +570,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
570 | snd_usb_stream_disconnect(p); | 570 | snd_usb_stream_disconnect(p); |
571 | } | 571 | } |
572 | /* release the endpoint resources */ | 572 | /* release the endpoint resources */ |
573 | list_for_each(p, &chip->ep_list) { | 573 | list_for_each_safe(p, n, &chip->ep_list) { |
574 | snd_usb_endpoint_free(p); | 574 | snd_usb_endpoint_free(p); |
575 | } | 575 | } |
576 | /* release the midi resources */ | 576 | /* release the midi resources */ |
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index c41181202688..d6e2bb49c59c 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -141,7 +141,7 @@ int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep) | |||
141 | * | 141 | * |
142 | * For implicit feedback, next_packet_size() is unused. | 142 | * For implicit feedback, next_packet_size() is unused. |
143 | */ | 143 | */ |
144 | static int next_packet_size(struct snd_usb_endpoint *ep) | 144 | int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) |
145 | { | 145 | { |
146 | unsigned long flags; | 146 | unsigned long flags; |
147 | int ret; | 147 | int ret; |
@@ -177,15 +177,6 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep, | |||
177 | ep->retire_data_urb(ep->data_subs, urb); | 177 | ep->retire_data_urb(ep->data_subs, urb); |
178 | } | 178 | } |
179 | 179 | ||
180 | static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep, | ||
181 | struct snd_urb_ctx *ctx) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | for (i = 0; i < ctx->packets; ++i) | ||
186 | ctx->packet_size[i] = next_packet_size(ep); | ||
187 | } | ||
188 | |||
189 | /* | 180 | /* |
190 | * Prepare a PLAYBACK urb for submission to the bus. | 181 | * Prepare a PLAYBACK urb for submission to the bus. |
191 | */ | 182 | */ |
@@ -370,7 +361,6 @@ static void snd_complete_urb(struct urb *urb) | |||
370 | goto exit_clear; | 361 | goto exit_clear; |
371 | } | 362 | } |
372 | 363 | ||
373 | prepare_outbound_urb_sizes(ep, ctx); | ||
374 | prepare_outbound_urb(ep, ctx); | 364 | prepare_outbound_urb(ep, ctx); |
375 | } else { | 365 | } else { |
376 | retire_inbound_urb(ep, ctx); | 366 | retire_inbound_urb(ep, ctx); |
@@ -799,7 +789,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | |||
799 | /** | 789 | /** |
800 | * snd_usb_endpoint_start: start an snd_usb_endpoint | 790 | * snd_usb_endpoint_start: start an snd_usb_endpoint |
801 | * | 791 | * |
802 | * @ep: the endpoint to start | 792 | * @ep: the endpoint to start |
793 | * @can_sleep: flag indicating whether the operation is executed in | ||
794 | * non-atomic context | ||
803 | * | 795 | * |
804 | * A call to this function will increment the use count of the endpoint. | 796 | * A call to this function will increment the use count of the endpoint. |
805 | * In case it is not already running, the URBs for this endpoint will be | 797 | * In case it is not already running, the URBs for this endpoint will be |
@@ -809,7 +801,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | |||
809 | * | 801 | * |
810 | * Returns an error if the URB submission failed, 0 in all other cases. | 802 | * Returns an error if the URB submission failed, 0 in all other cases. |
811 | */ | 803 | */ |
812 | int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) | 804 | int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep) |
813 | { | 805 | { |
814 | int err; | 806 | int err; |
815 | unsigned int i; | 807 | unsigned int i; |
@@ -821,6 +813,11 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) | |||
821 | if (++ep->use_count != 1) | 813 | if (++ep->use_count != 1) |
822 | return 0; | 814 | return 0; |
823 | 815 | ||
816 | /* just to be sure */ | ||
817 | deactivate_urbs(ep, 0, can_sleep); | ||
818 | if (can_sleep) | ||
819 | wait_clear_urbs(ep); | ||
820 | |||
824 | ep->active_mask = 0; | 821 | ep->active_mask = 0; |
825 | ep->unlink_mask = 0; | 822 | ep->unlink_mask = 0; |
826 | ep->phase = 0; | 823 | ep->phase = 0; |
@@ -850,7 +847,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) | |||
850 | goto __error; | 847 | goto __error; |
851 | 848 | ||
852 | if (usb_pipeout(ep->pipe)) { | 849 | if (usb_pipeout(ep->pipe)) { |
853 | prepare_outbound_urb_sizes(ep, urb->context); | ||
854 | prepare_outbound_urb(ep, urb->context); | 850 | prepare_outbound_urb(ep, urb->context); |
855 | } else { | 851 | } else { |
856 | prepare_inbound_urb(ep, urb->context); | 852 | prepare_inbound_urb(ep, urb->context); |
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index ee2723fb174f..cbbbdf226d66 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h | |||
@@ -13,7 +13,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | |||
13 | struct audioformat *fmt, | 13 | struct audioformat *fmt, |
14 | struct snd_usb_endpoint *sync_ep); | 14 | struct snd_usb_endpoint *sync_ep); |
15 | 15 | ||
16 | int snd_usb_endpoint_start(struct snd_usb_endpoint *ep); | 16 | int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep); |
17 | void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, | 17 | void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, |
18 | int force, int can_sleep, int wait); | 18 | int force, int can_sleep, int wait); |
19 | int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); | 19 | int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); |
@@ -21,6 +21,7 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); | |||
21 | void snd_usb_endpoint_free(struct list_head *head); | 21 | void snd_usb_endpoint_free(struct list_head *head); |
22 | 22 | ||
23 | int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep); | 23 | int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep); |
24 | int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); | ||
24 | 25 | ||
25 | void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, | 26 | void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, |
26 | struct snd_usb_endpoint *sender, | 27 | struct snd_usb_endpoint *sender, |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 62ec808ed792..fd5e982fc98c 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -212,7 +212,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | |||
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | static int start_endpoints(struct snd_usb_substream *subs) | 215 | static int start_endpoints(struct snd_usb_substream *subs, int can_sleep) |
216 | { | 216 | { |
217 | int err; | 217 | int err; |
218 | 218 | ||
@@ -225,7 +225,7 @@ static int start_endpoints(struct snd_usb_substream *subs) | |||
225 | snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep); | 225 | snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep); |
226 | 226 | ||
227 | ep->data_subs = subs; | 227 | ep->data_subs = subs; |
228 | err = snd_usb_endpoint_start(ep); | 228 | err = snd_usb_endpoint_start(ep, can_sleep); |
229 | if (err < 0) { | 229 | if (err < 0) { |
230 | clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); | 230 | clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); |
231 | return err; | 231 | return err; |
@@ -236,10 +236,25 @@ static int start_endpoints(struct snd_usb_substream *subs) | |||
236 | !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { | 236 | !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { |
237 | struct snd_usb_endpoint *ep = subs->sync_endpoint; | 237 | struct snd_usb_endpoint *ep = subs->sync_endpoint; |
238 | 238 | ||
239 | if (subs->data_endpoint->iface != subs->sync_endpoint->iface || | ||
240 | subs->data_endpoint->alt_idx != subs->sync_endpoint->alt_idx) { | ||
241 | err = usb_set_interface(subs->dev, | ||
242 | subs->sync_endpoint->iface, | ||
243 | subs->sync_endpoint->alt_idx); | ||
244 | if (err < 0) { | ||
245 | snd_printk(KERN_ERR | ||
246 | "%d:%d:%d: cannot set interface (%d)\n", | ||
247 | subs->dev->devnum, | ||
248 | subs->sync_endpoint->iface, | ||
249 | subs->sync_endpoint->alt_idx, err); | ||
250 | return -EIO; | ||
251 | } | ||
252 | } | ||
253 | |||
239 | snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep); | 254 | snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep); |
240 | 255 | ||
241 | ep->sync_slave = subs->data_endpoint; | 256 | ep->sync_slave = subs->data_endpoint; |
242 | err = snd_usb_endpoint_start(ep); | 257 | err = snd_usb_endpoint_start(ep, can_sleep); |
243 | if (err < 0) { | 258 | if (err < 0) { |
244 | clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); | 259 | clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); |
245 | return err; | 260 | return err; |
@@ -544,13 +559,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
544 | subs->last_frame_number = 0; | 559 | subs->last_frame_number = 0; |
545 | runtime->delay = 0; | 560 | runtime->delay = 0; |
546 | 561 | ||
547 | /* clear the pending deactivation on the target EPs */ | ||
548 | deactivate_endpoints(subs); | ||
549 | |||
550 | /* for playback, submit the URBs now; otherwise, the first hwptr_done | 562 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
551 | * updates for all URBs would happen at the same time when starting */ | 563 | * updates for all URBs would happen at the same time when starting */ |
552 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) | 564 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) |
553 | return start_endpoints(subs); | 565 | return start_endpoints(subs, 1); |
554 | 566 | ||
555 | return 0; | 567 | return 0; |
556 | } | 568 | } |
@@ -1032,6 +1044,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, | |||
1032 | struct urb *urb) | 1044 | struct urb *urb) |
1033 | { | 1045 | { |
1034 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; | 1046 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; |
1047 | struct snd_usb_endpoint *ep = subs->data_endpoint; | ||
1035 | struct snd_urb_ctx *ctx = urb->context; | 1048 | struct snd_urb_ctx *ctx = urb->context; |
1036 | unsigned int counts, frames, bytes; | 1049 | unsigned int counts, frames, bytes; |
1037 | int i, stride, period_elapsed = 0; | 1050 | int i, stride, period_elapsed = 0; |
@@ -1043,7 +1056,11 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, | |||
1043 | urb->number_of_packets = 0; | 1056 | urb->number_of_packets = 0; |
1044 | spin_lock_irqsave(&subs->lock, flags); | 1057 | spin_lock_irqsave(&subs->lock, flags); |
1045 | for (i = 0; i < ctx->packets; i++) { | 1058 | for (i = 0; i < ctx->packets; i++) { |
1046 | counts = ctx->packet_size[i]; | 1059 | if (ctx->packet_size[i]) |
1060 | counts = ctx->packet_size[i]; | ||
1061 | else | ||
1062 | counts = snd_usb_endpoint_next_packet_size(ep); | ||
1063 | |||
1047 | /* set up descriptor */ | 1064 | /* set up descriptor */ |
1048 | urb->iso_frame_desc[i].offset = frames * stride; | 1065 | urb->iso_frame_desc[i].offset = frames * stride; |
1049 | urb->iso_frame_desc[i].length = counts * stride; | 1066 | urb->iso_frame_desc[i].length = counts * stride; |
@@ -1094,7 +1111,16 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, | |||
1094 | subs->hwptr_done += bytes; | 1111 | subs->hwptr_done += bytes; |
1095 | if (subs->hwptr_done >= runtime->buffer_size * stride) | 1112 | if (subs->hwptr_done >= runtime->buffer_size * stride) |
1096 | subs->hwptr_done -= runtime->buffer_size * stride; | 1113 | subs->hwptr_done -= runtime->buffer_size * stride; |
1114 | |||
1115 | /* update delay with exact number of samples queued */ | ||
1116 | runtime->delay = subs->last_delay; | ||
1097 | runtime->delay += frames; | 1117 | runtime->delay += frames; |
1118 | subs->last_delay = runtime->delay; | ||
1119 | |||
1120 | /* realign last_frame_number */ | ||
1121 | subs->last_frame_number = usb_get_current_frame_number(subs->dev); | ||
1122 | subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ | ||
1123 | |||
1098 | spin_unlock_irqrestore(&subs->lock, flags); | 1124 | spin_unlock_irqrestore(&subs->lock, flags); |
1099 | urb->transfer_buffer_length = bytes; | 1125 | urb->transfer_buffer_length = bytes; |
1100 | if (period_elapsed) | 1126 | if (period_elapsed) |
@@ -1112,12 +1138,26 @@ static void retire_playback_urb(struct snd_usb_substream *subs, | |||
1112 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; | 1138 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; |
1113 | int stride = runtime->frame_bits >> 3; | 1139 | int stride = runtime->frame_bits >> 3; |
1114 | int processed = urb->transfer_buffer_length / stride; | 1140 | int processed = urb->transfer_buffer_length / stride; |
1141 | int est_delay; | ||
1115 | 1142 | ||
1116 | spin_lock_irqsave(&subs->lock, flags); | 1143 | spin_lock_irqsave(&subs->lock, flags); |
1117 | if (processed > runtime->delay) | 1144 | est_delay = snd_usb_pcm_delay(subs, runtime->rate); |
1118 | runtime->delay = 0; | 1145 | /* update delay with exact number of samples played */ |
1146 | if (processed > subs->last_delay) | ||
1147 | subs->last_delay = 0; | ||
1119 | else | 1148 | else |
1120 | runtime->delay -= processed; | 1149 | subs->last_delay -= processed; |
1150 | runtime->delay = subs->last_delay; | ||
1151 | |||
1152 | /* | ||
1153 | * Report when delay estimate is off by more than 2ms. | ||
1154 | * The error should be lower than 2ms since the estimate relies | ||
1155 | * on two reads of a counter updated every ms. | ||
1156 | */ | ||
1157 | if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) | ||
1158 | snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", | ||
1159 | est_delay, subs->last_delay); | ||
1160 | |||
1121 | spin_unlock_irqrestore(&subs->lock, flags); | 1161 | spin_unlock_irqrestore(&subs->lock, flags); |
1122 | } | 1162 | } |
1123 | 1163 | ||
@@ -1175,7 +1215,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream | |||
1175 | 1215 | ||
1176 | switch (cmd) { | 1216 | switch (cmd) { |
1177 | case SNDRV_PCM_TRIGGER_START: | 1217 | case SNDRV_PCM_TRIGGER_START: |
1178 | err = start_endpoints(subs); | 1218 | err = start_endpoints(subs, 0); |
1179 | if (err < 0) | 1219 | if (err < 0) |
1180 | return err; | 1220 | return err; |
1181 | 1221 | ||