aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r--sound/usb/pcm.c82
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
264static 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
277static int deactivate_endpoints(struct snd_usb_substream *subs) 264static 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
935static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) 948static 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
1150int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) 1167static 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;