diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2012-09-13 08:41:01 -0600 | 
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-09-13 08:41:01 -0600 | 
| commit | 78890b5989d96ddce989cde929c45ceeded0fcaf (patch) | |
| tree | 4e2da81fc7c97f11aee174b1eedac110c9a68b3a /sound/usb/pcm.c | |
| parent | 1959ec5f82acbdf91425b41600f119ebecb5f6a8 (diff) | |
| parent | 55d512e245bc7699a8800e23df1a24195dd08217 (diff) | |
| download | olio-linux-3.10-78890b5989d96ddce989cde929c45ceeded0fcaf.tar.xz olio-linux-3.10-78890b5989d96ddce989cde929c45ceeded0fcaf.zip  | |
Merge commit 'v3.6-rc5' into next
* commit 'v3.6-rc5': (1098 commits)
  Linux 3.6-rc5
  HID: tpkbd: work even if the new Lenovo Keyboard driver is not configured
  Remove user-triggerable BUG from mpol_to_str
  xen/pciback: Fix proper FLR steps.
  uml: fix compile error in deliver_alarm()
  dj: memory scribble in logi_dj
  Fix order of arguments to compat_put_time[spec|val]
  xen: Use correct masking in xen_swiotlb_alloc_coherent.
  xen: fix logical error in tlb flushing
  xen/p2m: Fix one-off error in checking the P2M tree directory.
  powerpc: Don't use __put_user() in patch_instruction
  powerpc: Make sure IPI handlers see data written by IPI senders
  powerpc: Restore correct DSCR in context switch
  powerpc: Fix DSCR inheritance in copy_thread()
  powerpc: Keep thread.dscr and thread.dscr_inherit in sync
  powerpc: Update DSCR on all CPUs when writing sysfs dscr_default
  powerpc/powernv: Always go into nap mode when CPU is offline
  powerpc: Give hypervisor decrementer interrupts their own handler
  powerpc/vphn: Fix arch_update_cpu_topology() return value
  ARM: gemini: fix the gemini build
  ...
Conflicts:
	drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
	drivers/rapidio/devices/tsi721.c
Diffstat (limited to 'sound/usb/pcm.c')
| -rw-r--r-- | sound/usb/pcm.c | 61 | 
1 files changed, 52 insertions, 9 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index a1298f37942..fd5e982fc98 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,  	}  } -static int start_endpoints(struct snd_usb_substream *subs) +static int start_endpoints(struct snd_usb_substream *subs, int can_sleep)  {  	int err; @@ -225,7 +225,7 @@ static int start_endpoints(struct snd_usb_substream *subs)  		snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);  		ep->data_subs = subs; -		err = snd_usb_endpoint_start(ep); +		err = snd_usb_endpoint_start(ep, can_sleep);  		if (err < 0) {  			clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);  			return err; @@ -236,10 +236,25 @@ static int start_endpoints(struct snd_usb_substream *subs)  	    !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {  		struct snd_usb_endpoint *ep = subs->sync_endpoint; +		if (subs->data_endpoint->iface != subs->sync_endpoint->iface || +		    subs->data_endpoint->alt_idx != subs->sync_endpoint->alt_idx) { +			err = usb_set_interface(subs->dev, +						subs->sync_endpoint->iface, +						subs->sync_endpoint->alt_idx); +			if (err < 0) { +				snd_printk(KERN_ERR +					   "%d:%d:%d: cannot set interface (%d)\n", +					   subs->dev->devnum, +					   subs->sync_endpoint->iface, +					   subs->sync_endpoint->alt_idx, err); +				return -EIO; +			} +		} +  		snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);  		ep->sync_slave = subs->data_endpoint; -		err = snd_usb_endpoint_start(ep); +		err = snd_usb_endpoint_start(ep, can_sleep);  		if (err < 0) {  			clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);  			return err; @@ -547,7 +562,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)  	/* for playback, submit the URBs now; otherwise, the first hwptr_done  	 * updates for all URBs would happen at the same time when starting */  	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) -		return start_endpoints(subs); +		return start_endpoints(subs, 1);  	return 0;  } @@ -1029,6 +1044,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,  				 struct urb *urb)  {  	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; +	struct snd_usb_endpoint *ep = subs->data_endpoint;  	struct snd_urb_ctx *ctx = urb->context;  	unsigned int counts, frames, bytes;  	int i, stride, period_elapsed = 0; @@ -1040,7 +1056,11 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,  	urb->number_of_packets = 0;  	spin_lock_irqsave(&subs->lock, flags);  	for (i = 0; i < ctx->packets; i++) { -		counts = ctx->packet_size[i]; +		if (ctx->packet_size[i]) +			counts = ctx->packet_size[i]; +		else +			counts = snd_usb_endpoint_next_packet_size(ep); +  		/* set up descriptor */  		urb->iso_frame_desc[i].offset = frames * stride;  		urb->iso_frame_desc[i].length = counts * stride; @@ -1091,7 +1111,16 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,  	subs->hwptr_done += bytes;  	if (subs->hwptr_done >= runtime->buffer_size * stride)  		subs->hwptr_done -= runtime->buffer_size * stride; + +	/* update delay with exact number of samples queued */ +	runtime->delay = subs->last_delay;  	runtime->delay += frames; +	subs->last_delay = runtime->delay; + +	/* realign last_frame_number */ +	subs->last_frame_number = usb_get_current_frame_number(subs->dev); +	subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ +  	spin_unlock_irqrestore(&subs->lock, flags);  	urb->transfer_buffer_length = bytes;  	if (period_elapsed) @@ -1109,12 +1138,26 @@ static void retire_playback_urb(struct snd_usb_substream *subs,  	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;  	int stride = runtime->frame_bits >> 3;  	int processed = urb->transfer_buffer_length / stride; +	int est_delay;  	spin_lock_irqsave(&subs->lock, flags); -	if (processed > runtime->delay) -		runtime->delay = 0; +	est_delay = snd_usb_pcm_delay(subs, runtime->rate); +	/* update delay with exact number of samples played */ +	if (processed > subs->last_delay) +		subs->last_delay = 0;  	else -		runtime->delay -= processed; +		subs->last_delay -= processed; +	runtime->delay = subs->last_delay; + +	/* +	 * Report when delay estimate is off by more than 2ms. +	 * The error should be lower than 2ms since the estimate relies +	 * on two reads of a counter updated every ms. +	 */ +	if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) +		snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", +			est_delay, subs->last_delay); +  	spin_unlock_irqrestore(&subs->lock, flags);  } @@ -1172,7 +1215,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START: -		err = start_endpoints(subs); +		err = start_endpoints(subs, 0);  		if (err < 0)  			return err;  |