diff options
Diffstat (limited to 'sound/usb/pcm.c')
| -rw-r--r-- | sound/usb/pcm.c | 82 |
1 files changed, 50 insertions, 32 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index cdf8b7601973..a1298f379428 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
| @@ -261,19 +261,6 @@ static void stop_endpoints(struct snd_usb_substream *subs, | |||
| 261 | force, can_sleep, wait); | 261 | force, can_sleep, wait); |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | static int activate_endpoints(struct snd_usb_substream *subs) | ||
| 265 | { | ||
| 266 | if (subs->sync_endpoint) { | ||
| 267 | int ret; | ||
| 268 | |||
| 269 | ret = snd_usb_endpoint_activate(subs->sync_endpoint); | ||
| 270 | if (ret < 0) | ||
| 271 | return ret; | ||
| 272 | } | ||
| 273 | |||
| 274 | return snd_usb_endpoint_activate(subs->data_endpoint); | ||
| 275 | } | ||
| 276 | |||
| 277 | static int deactivate_endpoints(struct snd_usb_substream *subs) | 264 | static int deactivate_endpoints(struct snd_usb_substream *subs) |
| 278 | { | 265 | { |
| 279 | int reta, retb; | 266 | int reta, retb; |
| @@ -314,6 +301,33 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
| 314 | if (fmt == subs->cur_audiofmt) | 301 | if (fmt == subs->cur_audiofmt) |
| 315 | return 0; | 302 | return 0; |
| 316 | 303 | ||
| 304 | /* close the old interface */ | ||
| 305 | if (subs->interface >= 0 && subs->interface != fmt->iface) { | ||
| 306 | err = usb_set_interface(subs->dev, subs->interface, 0); | ||
| 307 | if (err < 0) { | ||
| 308 | snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed (%d)\n", | ||
| 309 | dev->devnum, fmt->iface, fmt->altsetting, err); | ||
| 310 | return -EIO; | ||
| 311 | } | ||
| 312 | subs->interface = -1; | ||
| 313 | subs->altset_idx = 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | /* set interface */ | ||
| 317 | if (subs->interface != fmt->iface || | ||
| 318 | subs->altset_idx != fmt->altset_idx) { | ||
| 319 | err = usb_set_interface(dev, fmt->iface, fmt->altsetting); | ||
| 320 | if (err < 0) { | ||
| 321 | snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed (%d)\n", | ||
| 322 | dev->devnum, fmt->iface, fmt->altsetting, err); | ||
| 323 | return -EIO; | ||
| 324 | } | ||
| 325 | snd_printdd(KERN_INFO "setting usb interface %d:%d\n", | ||
| 326 | fmt->iface, fmt->altsetting); | ||
| 327 | subs->interface = fmt->iface; | ||
| 328 | subs->altset_idx = fmt->altset_idx; | ||
| 329 | } | ||
| 330 | |||
| 317 | subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, | 331 | subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, |
| 318 | alts, fmt->endpoint, subs->direction, | 332 | alts, fmt->endpoint, subs->direction, |
| 319 | SND_USB_ENDPOINT_TYPE_DATA); | 333 | SND_USB_ENDPOINT_TYPE_DATA); |
| @@ -354,17 +368,21 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
| 354 | (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | 368 | (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && |
| 355 | get_endpoint(alts, 1)->bSynchAddress != 0 && | 369 | get_endpoint(alts, 1)->bSynchAddress != 0 && |
| 356 | !implicit_fb)) { | 370 | !implicit_fb)) { |
| 357 | snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", | 371 | snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n", |
| 358 | dev->devnum, fmt->iface, fmt->altsetting); | 372 | dev->devnum, fmt->iface, fmt->altsetting, |
| 373 | get_endpoint(alts, 1)->bmAttributes, | ||
| 374 | get_endpoint(alts, 1)->bLength, | ||
| 375 | get_endpoint(alts, 1)->bSynchAddress); | ||
| 359 | return -EINVAL; | 376 | return -EINVAL; |
| 360 | } | 377 | } |
| 361 | ep = get_endpoint(alts, 1)->bEndpointAddress; | 378 | ep = get_endpoint(alts, 1)->bEndpointAddress; |
| 362 | if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | 379 | if (!implicit_fb && |
| 380 | get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | ||
| 363 | (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || | 381 | (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || |
| 364 | (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) || | 382 | (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { |
| 365 | ( is_playback && !implicit_fb))) { | 383 | snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n", |
| 366 | snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", | 384 | dev->devnum, fmt->iface, fmt->altsetting, |
| 367 | dev->devnum, fmt->iface, fmt->altsetting); | 385 | is_playback, ep, get_endpoint(alts, 0)->bSynchAddress); |
| 368 | return -EINVAL; | 386 | return -EINVAL; |
| 369 | } | 387 | } |
| 370 | 388 | ||
| @@ -383,7 +401,7 @@ add_sync_ep: | |||
| 383 | subs->data_endpoint->sync_master = subs->sync_endpoint; | 401 | subs->data_endpoint->sync_master = subs->sync_endpoint; |
| 384 | } | 402 | } |
| 385 | 403 | ||
| 386 | if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0) | 404 | if ((err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt)) < 0) |
| 387 | return err; | 405 | return err; |
| 388 | 406 | ||
| 389 | subs->cur_audiofmt = fmt; | 407 | subs->cur_audiofmt = fmt; |
| @@ -446,7 +464,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
| 446 | struct usb_interface *iface; | 464 | struct usb_interface *iface; |
| 447 | iface = usb_ifnum_to_if(subs->dev, fmt->iface); | 465 | iface = usb_ifnum_to_if(subs->dev, fmt->iface); |
| 448 | alts = &iface->altsetting[fmt->altset_idx]; | 466 | alts = &iface->altsetting[fmt->altset_idx]; |
| 449 | ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate); | 467 | ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate); |
| 450 | if (ret < 0) | 468 | if (ret < 0) |
| 451 | return ret; | 469 | return ret; |
| 452 | subs->cur_rate = rate; | 470 | subs->cur_rate = rate; |
| @@ -456,12 +474,6 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
| 456 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 474 | mutex_lock(&subs->stream->chip->shutdown_mutex); |
| 457 | /* format changed */ | 475 | /* format changed */ |
| 458 | stop_endpoints(subs, 0, 0, 0); | 476 | stop_endpoints(subs, 0, 0, 0); |
| 459 | deactivate_endpoints(subs); | ||
| 460 | |||
| 461 | ret = activate_endpoints(subs); | ||
| 462 | if (ret < 0) | ||
| 463 | goto unlock; | ||
| 464 | |||
| 465 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt, | 477 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt, |
| 466 | subs->sync_endpoint); | 478 | subs->sync_endpoint); |
| 467 | if (ret < 0) | 479 | if (ret < 0) |
| @@ -496,6 +508,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
| 496 | subs->period_bytes = 0; | 508 | subs->period_bytes = 0; |
| 497 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 509 | mutex_lock(&subs->stream->chip->shutdown_mutex); |
| 498 | stop_endpoints(subs, 0, 1, 1); | 510 | stop_endpoints(subs, 0, 1, 1); |
| 511 | deactivate_endpoints(subs); | ||
| 499 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 512 | mutex_unlock(&subs->stream->chip->shutdown_mutex); |
| 500 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 513 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
| 501 | } | 514 | } |
| @@ -934,16 +947,20 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | |||
| 934 | 947 | ||
| 935 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | 948 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) |
| 936 | { | 949 | { |
| 937 | int ret; | ||
| 938 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); | 950 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); |
| 939 | struct snd_usb_substream *subs = &as->substream[direction]; | 951 | struct snd_usb_substream *subs = &as->substream[direction]; |
| 940 | 952 | ||
| 941 | stop_endpoints(subs, 0, 0, 0); | 953 | stop_endpoints(subs, 0, 0, 0); |
| 942 | ret = deactivate_endpoints(subs); | 954 | |
| 955 | if (!as->chip->shutdown && subs->interface >= 0) { | ||
| 956 | usb_set_interface(subs->dev, subs->interface, 0); | ||
| 957 | subs->interface = -1; | ||
| 958 | } | ||
| 959 | |||
| 943 | subs->pcm_substream = NULL; | 960 | subs->pcm_substream = NULL; |
| 944 | snd_usb_autosuspend(subs->stream->chip); | 961 | snd_usb_autosuspend(subs->stream->chip); |
| 945 | 962 | ||
| 946 | return ret; | 963 | return 0; |
| 947 | } | 964 | } |
| 948 | 965 | ||
| 949 | /* Since a URB can handle only a single linear buffer, we must use double | 966 | /* Since a URB can handle only a single linear buffer, we must use double |
| @@ -1147,7 +1164,8 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea | |||
| 1147 | return -EINVAL; | 1164 | return -EINVAL; |
| 1148 | } | 1165 | } |
| 1149 | 1166 | ||
| 1150 | int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) | 1167 | static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, |
| 1168 | int cmd) | ||
| 1151 | { | 1169 | { |
| 1152 | int err; | 1170 | int err; |
| 1153 | struct snd_usb_substream *subs = substream->runtime->private_data; | 1171 | struct snd_usb_substream *subs = substream->runtime->private_data; |
