Sound fixes for 3.5-rc7
Containing the regression fixes for USB-audio due to the transition to the new streaming logic, mostly found on Logitech webcams. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJQAZmyAAoJEGwxgFQ9KSmk1rYP/2njHeYx9rrnd2zcxwn5kO1Q Sig3Zl57wOQBEwVCvkUriJQlpmjF20Fyj3kyTRFfUCssffIGbpJ9BVektSCmI5fK bVGeGnssFGvUIlkdHLGNof5nPPoZE1w+FyvIZKlaAf1l3ji2RR36HgkPkD2C4und kIuSiCgaHV/+S3zHWkvOSshalOZh4zzuwuuxi+52yZkETo74gaO4fpp/FodII8ME 0SrfT55N3Pq++N4ZLYF8Q/ju+hWomVEXq+f2KXAh+5f58GYW04H36r+QwJfhq8zz OnDoupHOw58yTG+gv+ORyMNxrKgJUuiyb4hzNEZ3Gkn/yR3f7jh95x6IFkrGynqP 8/5rpRGohg7jiSaUuuRLr9suUBCBVVHEjnEU6QBLGjfL2eWm6vizT+l8sHBukicX tj6u7IH2kjCdv7H0F8B2jqYps+6v7kHYWDFkJMd/gF3X3xBm67f7HZCDYWxqE7nw ROIYjhcNaxFIA0EccKv6q6wJyCAul0M9QlCbAYM27jvFSC2ObzqvCpVMSwMBxomY EE/4FZYJIEDVULLIt4hw3i3imMAgx2btxb/zflRhkQY1s+TGrsxival075pr5Akz aje92WJo9+HFbdP9kvuIzIFOHHXZYekCLwxFoLbm+U4JEiCjCIDVYXhZhEfKP0Pi I/E5VX+jG2rhUMxWrET2 =W7/C -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
1daaa5e4ff
2 changed files with 43 additions and 91 deletions
|
@ -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,24 +928,15 @@ 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;
|
||||
clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
|
||||
|
||||
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 -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue