diff options
Diffstat (limited to 'sound/usb/endpoint.c')
| -rw-r--r-- | sound/usb/endpoint.c | 215 | 
1 files changed, 133 insertions, 82 deletions
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 93e970f2b3c..114e3e7ff51 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -33,7 +33,6 @@  #include "pcm.h"  #include "quirks.h" -#define EP_FLAG_ACTIVATED	0  #define EP_FLAG_RUNNING		1  #define EP_FLAG_STOPPING	2 @@ -334,8 +333,9 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)  		err = usb_submit_urb(ctx->urb, GFP_ATOMIC);  		if (err < 0) -			snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n", -				   ctx->index, err, ctx->urb); +			usb_audio_err(ep->chip, +				"Unable to submit urb #%d: %d (urb %p)\n", +				ctx->index, err, ctx->urb);  		else  			set_bit(ctx->index, &ep->active_mask);  	} @@ -388,7 +388,7 @@ static void snd_complete_urb(struct urb *urb)  	if (err == 0)  		return; -	snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err); +	usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err);  	//snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);  exit_clear: @@ -426,14 +426,15 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,  	list_for_each_entry(ep, &chip->ep_list, list) {  		if (ep->ep_num == ep_num &&  		    ep->iface == alts->desc.bInterfaceNumber && -		    ep->alt_idx == alts->desc.bAlternateSetting) { -			snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n", -					ep_num, ep->iface, ep->alt_idx, ep); +		    ep->altsetting == alts->desc.bAlternateSetting) { +			usb_audio_dbg(ep->chip, +				      "Re-using EP %x in iface %d,%d @%p\n", +					ep_num, ep->iface, ep->altsetting, ep);  			goto __exit_unlock;  		}  	} -	snd_printdd(KERN_DEBUG "Creating new %s %s endpoint #%x\n", +	usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n",  		    is_playback ? "playback" : "capture",  		    type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",  		    ep_num); @@ -447,7 +448,7 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,  	ep->type = type;  	ep->ep_num = ep_num;  	ep->iface = alts->desc.bInterfaceNumber; -	ep->alt_idx = alts->desc.bAlternateSetting; +	ep->altsetting = alts->desc.bAlternateSetting;  	INIT_LIST_HEAD(&ep->ready_playback_urbs);  	ep_num &= USB_ENDPOINT_NUMBER_MASK; @@ -470,6 +471,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,  			ep->syncinterval = 3;  		ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); + +		if (chip->usb_id == USB_ID(0x0644, 0x8038) /* TEAC UD-H01 */ && +		    ep->syncmaxsize == 4) +			ep->udh01_fb_quirk = 1;  	}  	list_add_tail(&ep->list, &chip->ep_list); @@ -497,8 +502,9 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)  	} while (time_before(jiffies, end_time));  	if (alive) -		snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n", -					alive, ep->ep_num); +		usb_audio_err(ep->chip, +			"timeout: still %d active urbs on EP #%x\n", +			alive, ep->ep_num);  	clear_bit(EP_FLAG_STOPPING, &ep->flags);  	return 0; @@ -574,11 +580,14 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,  			      snd_pcm_format_t pcm_format,  			      unsigned int channels,  			      unsigned int period_bytes, +			      unsigned int frames_per_period, +			      unsigned int periods_per_buffer,  			      struct audioformat *fmt,  			      struct snd_usb_endpoint *sync_ep)  { -	unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms; -	int is_playback = usb_pipeout(ep->pipe); +	unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb; +	unsigned int max_packs_per_period, urbs_per_period, urb_packs; +	unsigned int max_urbs, i;  	int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;  	if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { @@ -611,58 +620,81 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,  	else  		ep->curpacksize = maxsize; -	if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) +	if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) {  		packs_per_ms = 8 >> ep->datainterval; -	else -		packs_per_ms = 1; - -	if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) { -		urb_packs = max(ep->chip->nrpacks, 1); -		urb_packs = min(urb_packs, (unsigned int) MAX_PACKS); +		max_packs_per_urb = MAX_PACKS_HS;  	} else { -		urb_packs = 1; +		packs_per_ms = 1; +		max_packs_per_urb = MAX_PACKS;  	} +	if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep)) +		max_packs_per_urb = min(max_packs_per_urb, +					1U << sync_ep->syncinterval); +	max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval); -	urb_packs *= packs_per_ms; +	/* +	 * Capture endpoints need to use small URBs because there's no way +	 * to tell in advance where the next period will end, and we don't +	 * want the next URB to complete much after the period ends. +	 * +	 * Playback endpoints with implicit sync much use the same parameters +	 * as their corresponding capture endpoint. +	 */ +	if (usb_pipein(ep->pipe) || +			snd_usb_endpoint_implicit_feedback_sink(ep)) { -	if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep)) -		urb_packs = min(urb_packs, 1U << sync_ep->syncinterval); +		urb_packs = packs_per_ms; +		/* +		 * Wireless devices can poll at a max rate of once per 4ms. +		 * For dataintervals less than 5, increase the packet count to +		 * allow the host controller to use bursting to fill in the +		 * gaps. +		 */ +		if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_WIRELESS) { +			int interval = ep->datainterval; +			while (interval < 5) { +				urb_packs <<= 1; +				++interval; +			} +		} +		/* make capture URBs <= 1 ms and smaller than a period */ +		urb_packs = min(max_packs_per_urb, urb_packs); +		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) +			urb_packs >>= 1; +		ep->nurbs = MAX_URBS; -	/* decide how many packets to be used */ -	if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) { -		unsigned int minsize, maxpacks; +	/* +	 * Playback endpoints without implicit sync are adjusted so that +	 * a period fits as evenly as possible in the smallest number of +	 * URBs.  The total number of URBs is adjusted to the size of the +	 * ALSA buffer, subject to the MAX_URBS and MAX_QUEUE limits. +	 */ +	} else {  		/* determine how small a packet can be */ -		minsize = (ep->freqn >> (16 - ep->datainterval)) -			  * (frame_bits >> 3); +		minsize = (ep->freqn >> (16 - ep->datainterval)) * +				(frame_bits >> 3);  		/* with sync from device, assume it can be 12% lower */  		if (sync_ep)  			minsize -= minsize >> 3;  		minsize = max(minsize, 1u); -		total_packs = (period_bytes + minsize - 1) / minsize; -		/* we need at least two URBs for queueing */ -		if (total_packs < 2) { -			total_packs = 2; -		} else { -			/* and we don't want too long a queue either */ -			maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2); -			total_packs = min(total_packs, maxpacks); -		} -	} else { -		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) -			urb_packs >>= 1; -		total_packs = MAX_URBS * urb_packs; -	} -	ep->nurbs = (total_packs + urb_packs - 1) / urb_packs; -	if (ep->nurbs > MAX_URBS) { -		/* too much... */ -		ep->nurbs = MAX_URBS; -		total_packs = MAX_URBS * urb_packs; -	} else if (ep->nurbs < 2) { -		/* too little - we need at least two packets -		 * to ensure contiguous playback/capture -		 */ -		ep->nurbs = 2; +		/* how many packets will contain an entire ALSA period? */ +		max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize); + +		/* how many URBs will contain a period? */ +		urbs_per_period = DIV_ROUND_UP(max_packs_per_period, +				max_packs_per_urb); +		/* how many packets are needed in each URB? */ +		urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period); + +		/* limit the number of frames in a single URB */ +		ep->max_urb_frames = DIV_ROUND_UP(frames_per_period, +					urbs_per_period); + +		/* try to use enough URBs to contain an entire ALSA buffer */ +		max_urbs = min((unsigned) MAX_URBS, +				MAX_QUEUE * packs_per_ms / urb_packs); +		ep->nurbs = min(max_urbs, urbs_per_period * periods_per_buffer);  	}  	/* allocate and initialize data urbs */ @@ -670,8 +702,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,  		struct snd_urb_ctx *u = &ep->urb[i];  		u->index = i;  		u->ep = ep; -		u->packets = (i + 1) * total_packs / ep->nurbs -			- i * total_packs / ep->nurbs; +		u->packets = urb_packs;  		u->buffer_size = maxsize * u->packets;  		if (fmt->fmt_type == UAC_FORMAT_TYPE_II) @@ -703,8 +734,7 @@ out_of_memory:  /*   * configure a sync endpoint   */ -static int sync_ep_set_params(struct snd_usb_endpoint *ep, -			      struct audioformat *fmt) +static int sync_ep_set_params(struct snd_usb_endpoint *ep)  {  	int i; @@ -748,6 +778,8 @@ out_of_memory:   * @pcm_format: the audio fomat.   * @channels: the number of audio channels.   * @period_bytes: the number of bytes in one alsa period. + * @period_frames: the number of frames in one alsa period. + * @buffer_periods: the number of periods in one alsa buffer.   * @rate: the frame rate.   * @fmt: the USB audio format information   * @sync_ep: the sync endpoint to use, if any @@ -760,6 +792,8 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,  				snd_pcm_format_t pcm_format,  				unsigned int channels,  				unsigned int period_bytes, +				unsigned int period_frames, +				unsigned int buffer_periods,  				unsigned int rate,  				struct audioformat *fmt,  				struct snd_usb_endpoint *sync_ep) @@ -767,8 +801,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,  	int err;  	if (ep->use_count != 0) { -		snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n", -			   ep->ep_num); +		usb_audio_warn(ep->chip, +			 "Unable to change format on ep #%x: already in use\n", +			 ep->ep_num);  		return -EBUSY;  	} @@ -793,17 +828,19 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,  	switch (ep->type) {  	case  SND_USB_ENDPOINT_TYPE_DATA:  		err = data_ep_set_params(ep, pcm_format, channels, -					 period_bytes, fmt, sync_ep); +					 period_bytes, period_frames, +					 buffer_periods, fmt, sync_ep);  		break;  	case  SND_USB_ENDPOINT_TYPE_SYNC: -		err = sync_ep_set_params(ep, fmt); +		err = sync_ep_set_params(ep);  		break;  	default:  		err = -EINVAL;  	} -	snd_printdd(KERN_DEBUG "Setting params for ep #%x (type %d, %d urbs), ret=%d\n", -		   ep->ep_num, ep->type, ep->nurbs, err); +	usb_audio_dbg(ep->chip, +		"Setting params for ep #%x (type %d, %d urbs), ret=%d\n", +		ep->ep_num, ep->type, ep->nurbs, err);  	return err;  } @@ -878,8 +915,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep)  		err = usb_submit_urb(urb, GFP_ATOMIC);  		if (err < 0) { -			snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n", -				   i, err, usb_error_string(err)); +			usb_audio_err(ep->chip, +				"cannot submit urb %d, error %d: %s\n", +				i, err, usb_error_string(err));  			goto __error;  		}  		set_bit(i, &ep->active_mask); @@ -931,28 +969,34 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)   *   * @ep: the endpoint to deactivate   * - * If the endpoint is not currently in use, this functions will select the - * alternate interface setting 0 for the interface of this endpoint. + * If the endpoint is not currently in use, this functions will + * deactivate its associated URBs.   *   * In case of any active users, this functions does nothing. - * - * Returns an error if usb_set_interface() failed, 0 in all other - * cases.   */ -int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) +void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)  {  	if (!ep) -		return -EINVAL; - -	deactivate_urbs(ep, true); -	wait_clear_urbs(ep); +		return;  	if (ep->use_count != 0) -		return 0; +		return; -	clear_bit(EP_FLAG_ACTIVATED, &ep->flags); +	deactivate_urbs(ep, true); +	wait_clear_urbs(ep); +} -	return 0; +/** + * snd_usb_endpoint_release: Tear down an snd_usb_endpoint + * + * @ep: the endpoint to release + * + * This function does not care for the endpoint's use count but will tear + * down all the streaming URBs immediately. + */ +void snd_usb_endpoint_release(struct snd_usb_endpoint *ep) +{ +	release_urbs(ep, 1);  }  /** @@ -960,15 +1004,13 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)   *   * @ep: the list header of the endpoint to free   * - * This function does not care for the endpoint's use count but will tear - * down all the streaming URBs immediately and free all resources. + * This free all resources of the given ep.   */  void snd_usb_endpoint_free(struct list_head *head)  {  	struct snd_usb_endpoint *ep;  	ep = list_entry(head, struct snd_usb_endpoint, list); -	release_urbs(ep, 1);  	kfree(ep);  } @@ -1078,7 +1120,16 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,  	if (f == 0)  		return; -	if (unlikely(ep->freqshift == INT_MIN)) { +	if (unlikely(sender->udh01_fb_quirk)) { +		/* +		 * The TEAC UD-H01 firmware sometimes changes the feedback value +		 * by +/- 0x1.0000. +		 */ +		if (f < ep->freqn - 0x8000) +			f += 0x10000; +		else if (f > ep->freqn + 0x8000) +			f -= 0x10000; +	} else if (unlikely(ep->freqshift == INT_MIN)) {  		/*  		 * The first time we see a feedback value, determine its format  		 * by shifting it left or right until it matches the nominal  | 
