Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1daaa5e4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull sound fixes from Takashi Iwai:
 "Containing the regression fixes for USB-audio due to the transition to
  the new streaming logic, mostly found on Logitech webcams."

* tag 'sound-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: snd-usb: move calls to usb_set_interface
  ALSA: usb-audio: Fix the first PCM interface assignment
parents c5b01acf 68e67f40
Loading
Loading
Loading
Loading
+6 −67
Original line number Diff line number Diff line
@@ -414,7 +414,7 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
{
	struct list_head *p;
	struct snd_usb_endpoint *ep;
	int ret, is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
	int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;

	mutex_lock(&chip->mutex);

@@ -434,16 +434,6 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
		    type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
		    ep_num);

	/* select the alt setting once so the endpoints become valid */
	ret = usb_set_interface(chip->dev, alts->desc.bInterfaceNumber,
				alts->desc.bAlternateSetting);
	if (ret < 0) {
		snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
					__func__, ret);
		ep = NULL;
		goto __exit_unlock;
	}

	ep = kzalloc(sizeof(*ep), GFP_KERNEL);
	if (!ep)
		goto __exit_unlock;
@@ -831,9 +821,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
	if (++ep->use_count != 1)
		return 0;

	if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
		return -EINVAL;

	/* just to be sure */
	deactivate_urbs(ep, 0, 1);
	wait_clear_urbs(ep);
@@ -911,9 +898,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
	if (snd_BUG_ON(ep->use_count == 0))
		return;

	if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
		return;

	if (--ep->use_count == 0) {
		deactivate_urbs(ep, force, can_sleep);
		ep->data_subs = NULL;
@@ -926,42 +910,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
	}
}

/**
 * snd_usb_endpoint_activate: activate an snd_usb_endpoint
 *
 * @ep: the endpoint to activate
 *
 * If the endpoint is not currently in use, this functions will select the
 * correct alternate interface setting for the interface of this endpoint.
 *
 * 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_activate(struct snd_usb_endpoint *ep)
{
	if (ep->use_count != 0)
		return 0;

	if (!ep->chip->shutdown &&
	    !test_and_set_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
		int ret;

		ret = usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
		if (ret < 0) {
			snd_printk(KERN_ERR "%s() usb_set_interface() failed, ret = %d\n",
						__func__, ret);
			clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
			return ret;
		}

		return 0;
	}

	return -EBUSY;
}

/**
 * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint
 *
@@ -980,26 +928,17 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
	if (!ep)
		return -EINVAL;

	deactivate_urbs(ep, 1, 1);
	wait_clear_urbs(ep);

	if (ep->use_count != 0)
		return 0;

	if (!ep->chip->shutdown &&
	    test_and_clear_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
		int ret;

		ret = usb_set_interface(ep->chip->dev, ep->iface, 0);
		if (ret < 0) {
			snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
						__func__, ret);
			return ret;
		}
	clear_bit(EP_FLAG_ACTIVATED, &ep->flags);

	return 0;
}

	return -EBUSY;
}

/**
 * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
 *
+37 −24
Original line number Diff line number Diff line
@@ -261,19 +261,6 @@ static void stop_endpoints(struct snd_usb_substream *subs,
				      force, can_sleep, wait);
}

static int activate_endpoints(struct snd_usb_substream *subs)
{
	if (subs->sync_endpoint) {
		int ret;

		ret = snd_usb_endpoint_activate(subs->sync_endpoint);
		if (ret < 0)
			return ret;
	}

	return snd_usb_endpoint_activate(subs->data_endpoint);
}

static int deactivate_endpoints(struct snd_usb_substream *subs)
{
	int reta, retb;
@@ -314,6 +301,33 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
	if (fmt == subs->cur_audiofmt)
		return 0;

	/* close the old interface */
	if (subs->interface >= 0 && subs->interface != fmt->iface) {
		err = usb_set_interface(subs->dev, subs->interface, 0);
		if (err < 0) {
			snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed (%d)\n",
				dev->devnum, fmt->iface, fmt->altsetting, err);
			return -EIO;
		}
		subs->interface = -1;
		subs->altset_idx = 0;
	}

	/* set interface */
	if (subs->interface != fmt->iface ||
	    subs->altset_idx != fmt->altset_idx) {
		err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
		if (err < 0) {
			snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed (%d)\n",
				   dev->devnum, fmt->iface, fmt->altsetting, err);
			return -EIO;
		}
		snd_printdd(KERN_INFO "setting usb interface %d:%d\n",
				fmt->iface, fmt->altsetting);
		subs->interface = fmt->iface;
		subs->altset_idx = fmt->altset_idx;
	}

	subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
						   alts, fmt->endpoint, subs->direction,
						   SND_USB_ENDPOINT_TYPE_DATA);
@@ -387,7 +401,7 @@ add_sync_ep:
		subs->data_endpoint->sync_master = subs->sync_endpoint;
	}

	if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
	if ((err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt)) < 0)
		return err;

	subs->cur_audiofmt = fmt;
@@ -450,7 +464,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
		struct usb_interface *iface;
		iface = usb_ifnum_to_if(subs->dev, fmt->iface);
		alts = &iface->altsetting[fmt->altset_idx];
		ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate);
		ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate);
		if (ret < 0)
			return ret;
		subs->cur_rate = rate;
@@ -460,12 +474,6 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
		mutex_lock(&subs->stream->chip->shutdown_mutex);
		/* format changed */
		stop_endpoints(subs, 0, 0, 0);
		deactivate_endpoints(subs);

		ret = activate_endpoints(subs);
		if (ret < 0)
			goto unlock;

		ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
						  subs->sync_endpoint);
		if (ret < 0)
@@ -500,6 +508,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
	subs->period_bytes = 0;
	mutex_lock(&subs->stream->chip->shutdown_mutex);
	stop_endpoints(subs, 0, 1, 1);
	deactivate_endpoints(subs);
	mutex_unlock(&subs->stream->chip->shutdown_mutex);
	return snd_pcm_lib_free_vmalloc_buffer(substream);
}
@@ -938,16 +947,20 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)

static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
{
	int ret;
	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
	struct snd_usb_substream *subs = &as->substream[direction];

	stop_endpoints(subs, 0, 0, 0);
	ret = deactivate_endpoints(subs);

	if (!as->chip->shutdown && subs->interface >= 0) {
		usb_set_interface(subs->dev, subs->interface, 0);
		subs->interface = -1;
	}

	subs->pcm_substream = NULL;
	snd_usb_autosuspend(subs->stream->chip);

	return ret;
	return 0;
}

/* Since a URB can handle only a single linear buffer, we must use double