Commit 1daaa5e4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

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
...@@ -414,7 +414,7 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, ...@@ -414,7 +414,7 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
{ {
struct list_head *p; struct list_head *p;
struct snd_usb_endpoint *ep; 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); mutex_lock(&chip->mutex);
...@@ -434,16 +434,6 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, ...@@ -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", type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
ep_num); 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); ep = kzalloc(sizeof(*ep), GFP_KERNEL);
if (!ep) if (!ep)
goto __exit_unlock; goto __exit_unlock;
...@@ -831,9 +821,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) ...@@ -831,9 +821,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
if (++ep->use_count != 1) if (++ep->use_count != 1)
return 0; return 0;
if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
return -EINVAL;
/* just to be sure */ /* just to be sure */
deactivate_urbs(ep, 0, 1); deactivate_urbs(ep, 0, 1);
wait_clear_urbs(ep); wait_clear_urbs(ep);
...@@ -911,9 +898,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, ...@@ -911,9 +898,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
if (snd_BUG_ON(ep->use_count == 0)) if (snd_BUG_ON(ep->use_count == 0))
return; return;
if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
return;
if (--ep->use_count == 0) { if (--ep->use_count == 0) {
deactivate_urbs(ep, force, can_sleep); deactivate_urbs(ep, force, can_sleep);
ep->data_subs = NULL; ep->data_subs = NULL;
...@@ -926,42 +910,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, ...@@ -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 * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint
* *
...@@ -980,24 +928,15 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) ...@@ -980,24 +928,15 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
if (!ep) if (!ep)
return -EINVAL; return -EINVAL;
deactivate_urbs(ep, 1, 1);
wait_clear_urbs(ep);
if (ep->use_count != 0) if (ep->use_count != 0)
return 0; return 0;
if (!ep->chip->shutdown && clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
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;
}
return 0; return 0;
}
return -EBUSY;
} }
/** /**
......
...@@ -261,19 +261,6 @@ static void stop_endpoints(struct snd_usb_substream *subs, ...@@ -261,19 +261,6 @@ static void stop_endpoints(struct snd_usb_substream *subs,
force, can_sleep, wait); 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) static int deactivate_endpoints(struct snd_usb_substream *subs)
{ {
int reta, retb; int reta, retb;
...@@ -314,6 +301,33 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) ...@@ -314,6 +301,33 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (fmt == subs->cur_audiofmt) if (fmt == subs->cur_audiofmt)
return 0; 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, subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
alts, fmt->endpoint, subs->direction, alts, fmt->endpoint, subs->direction,
SND_USB_ENDPOINT_TYPE_DATA); SND_USB_ENDPOINT_TYPE_DATA);
...@@ -387,7 +401,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) ...@@ -387,7 +401,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
subs->data_endpoint->sync_master = subs->sync_endpoint; 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; return err;
subs->cur_audiofmt = fmt; subs->cur_audiofmt = fmt;
...@@ -450,7 +464,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, ...@@ -450,7 +464,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
struct usb_interface *iface; struct usb_interface *iface;
iface = usb_ifnum_to_if(subs->dev, fmt->iface); iface = usb_ifnum_to_if(subs->dev, fmt->iface);
alts = &iface->altsetting[fmt->altset_idx]; 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) if (ret < 0)
return ret; return ret;
subs->cur_rate = rate; subs->cur_rate = rate;
...@@ -460,12 +474,6 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, ...@@ -460,12 +474,6 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
mutex_lock(&subs->stream->chip->shutdown_mutex); mutex_lock(&subs->stream->chip->shutdown_mutex);
/* format changed */ /* format changed */
stop_endpoints(subs, 0, 0, 0); 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, ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
subs->sync_endpoint); subs->sync_endpoint);
if (ret < 0) if (ret < 0)
...@@ -500,6 +508,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) ...@@ -500,6 +508,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
subs->period_bytes = 0; subs->period_bytes = 0;
mutex_lock(&subs->stream->chip->shutdown_mutex); mutex_lock(&subs->stream->chip->shutdown_mutex);
stop_endpoints(subs, 0, 1, 1); stop_endpoints(subs, 0, 1, 1);
deactivate_endpoints(subs);
mutex_unlock(&subs->stream->chip->shutdown_mutex); mutex_unlock(&subs->stream->chip->shutdown_mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream); 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) ...@@ -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) 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_stream *as = snd_pcm_substream_chip(substream);
struct snd_usb_substream *subs = &as->substream[direction]; struct snd_usb_substream *subs = &as->substream[direction];
stop_endpoints(subs, 0, 0, 0); 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; subs->pcm_substream = NULL;
snd_usb_autosuspend(subs->stream->chip); snd_usb_autosuspend(subs->stream->chip);
return ret; return 0;
} }
/* Since a URB can handle only a single linear buffer, we must use double /* Since a URB can handle only a single linear buffer, we must use double
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment