diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 14 | ||||
-rw-r--r-- | sound/usb/card.h | 1 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 13 | ||||
-rw-r--r-- | sound/usb/endpoint.h | 1 | ||||
-rw-r--r-- | sound/usb/mixer.c | 65 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 58 | ||||
-rw-r--r-- | sound/usb/pcm.c | 56 | ||||
-rw-r--r-- | sound/usb/proc.c | 4 | ||||
-rw-r--r-- | sound/usb/stream.c | 1 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 2 |
10 files changed, 159 insertions, 56 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 561bb74fd364..dbf7999d18b4 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -339,7 +339,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
339 | } | 339 | } |
340 | 340 | ||
341 | mutex_init(&chip->mutex); | 341 | mutex_init(&chip->mutex); |
342 | mutex_init(&chip->shutdown_mutex); | 342 | init_rwsem(&chip->shutdown_rwsem); |
343 | chip->index = idx; | 343 | chip->index = idx; |
344 | chip->dev = dev; | 344 | chip->dev = dev; |
345 | chip->card = card; | 345 | chip->card = card; |
@@ -559,9 +559,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
559 | return; | 559 | return; |
560 | 560 | ||
561 | card = chip->card; | 561 | card = chip->card; |
562 | mutex_lock(®ister_mutex); | 562 | down_write(&chip->shutdown_rwsem); |
563 | mutex_lock(&chip->shutdown_mutex); | ||
564 | chip->shutdown = 1; | 563 | chip->shutdown = 1; |
564 | up_write(&chip->shutdown_rwsem); | ||
565 | |||
566 | mutex_lock(®ister_mutex); | ||
565 | chip->num_interfaces--; | 567 | chip->num_interfaces--; |
566 | if (chip->num_interfaces <= 0) { | 568 | if (chip->num_interfaces <= 0) { |
567 | snd_card_disconnect(card); | 569 | snd_card_disconnect(card); |
@@ -582,11 +584,9 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
582 | snd_usb_mixer_disconnect(p); | 584 | snd_usb_mixer_disconnect(p); |
583 | } | 585 | } |
584 | usb_chip[chip->index] = NULL; | 586 | usb_chip[chip->index] = NULL; |
585 | mutex_unlock(&chip->shutdown_mutex); | ||
586 | mutex_unlock(®ister_mutex); | 587 | mutex_unlock(®ister_mutex); |
587 | snd_card_free_when_closed(card); | 588 | snd_card_free_when_closed(card); |
588 | } else { | 589 | } else { |
589 | mutex_unlock(&chip->shutdown_mutex); | ||
590 | mutex_unlock(®ister_mutex); | 590 | mutex_unlock(®ister_mutex); |
591 | } | 591 | } |
592 | } | 592 | } |
@@ -618,16 +618,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) | |||
618 | { | 618 | { |
619 | int err = -ENODEV; | 619 | int err = -ENODEV; |
620 | 620 | ||
621 | down_read(&chip->shutdown_rwsem); | ||
621 | if (!chip->shutdown && !chip->probing) | 622 | if (!chip->shutdown && !chip->probing) |
622 | err = usb_autopm_get_interface(chip->pm_intf); | 623 | err = usb_autopm_get_interface(chip->pm_intf); |
624 | up_read(&chip->shutdown_rwsem); | ||
623 | 625 | ||
624 | return err; | 626 | return err; |
625 | } | 627 | } |
626 | 628 | ||
627 | void snd_usb_autosuspend(struct snd_usb_audio *chip) | 629 | void snd_usb_autosuspend(struct snd_usb_audio *chip) |
628 | { | 630 | { |
631 | down_read(&chip->shutdown_rwsem); | ||
629 | if (!chip->shutdown && !chip->probing) | 632 | if (!chip->shutdown && !chip->probing) |
630 | usb_autopm_put_interface(chip->pm_intf); | 633 | usb_autopm_put_interface(chip->pm_intf); |
634 | up_read(&chip->shutdown_rwsem); | ||
631 | } | 635 | } |
632 | 636 | ||
633 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | 637 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) |
diff --git a/sound/usb/card.h b/sound/usb/card.h index afa4f9e9b27a..814cb357ff88 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h | |||
@@ -126,6 +126,7 @@ struct snd_usb_substream { | |||
126 | struct snd_usb_endpoint *sync_endpoint; | 126 | struct snd_usb_endpoint *sync_endpoint; |
127 | unsigned long flags; | 127 | unsigned long flags; |
128 | bool need_setup_ep; /* (re)configure EP at prepare? */ | 128 | bool need_setup_ep; /* (re)configure EP at prepare? */ |
129 | unsigned int speed; /* USB_SPEED_XXX */ | ||
129 | 130 | ||
130 | u64 formats; /* format bitmasks (all or'ed) */ | 131 | u64 formats; /* format bitmasks (all or'ed) */ |
131 | unsigned int num_formats; /* number of supported audio formats (list) */ | 132 | unsigned int num_formats; /* number of supported audio formats (list) */ |
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 7f78c6d782b0..34de6f2faf61 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #define EP_FLAG_ACTIVATED 0 | 36 | #define EP_FLAG_ACTIVATED 0 |
37 | #define EP_FLAG_RUNNING 1 | 37 | #define EP_FLAG_RUNNING 1 |
38 | #define EP_FLAG_STOPPING 2 | ||
38 | 39 | ||
39 | /* | 40 | /* |
40 | * snd_usb_endpoint is a model that abstracts everything related to an | 41 | * snd_usb_endpoint is a model that abstracts everything related to an |
@@ -502,10 +503,20 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep) | |||
502 | if (alive) | 503 | if (alive) |
503 | snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n", | 504 | snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n", |
504 | alive, ep->ep_num); | 505 | alive, ep->ep_num); |
506 | clear_bit(EP_FLAG_STOPPING, &ep->flags); | ||
505 | 507 | ||
506 | return 0; | 508 | return 0; |
507 | } | 509 | } |
508 | 510 | ||
511 | /* sync the pending stop operation; | ||
512 | * this function itself doesn't trigger the stop operation | ||
513 | */ | ||
514 | void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep) | ||
515 | { | ||
516 | if (ep && test_bit(EP_FLAG_STOPPING, &ep->flags)) | ||
517 | wait_clear_urbs(ep); | ||
518 | } | ||
519 | |||
509 | /* | 520 | /* |
510 | * unlink active urbs. | 521 | * unlink active urbs. |
511 | */ | 522 | */ |
@@ -918,6 +929,8 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, | |||
918 | 929 | ||
919 | if (wait) | 930 | if (wait) |
920 | wait_clear_urbs(ep); | 931 | wait_clear_urbs(ep); |
932 | else | ||
933 | set_bit(EP_FLAG_STOPPING, &ep->flags); | ||
921 | } | 934 | } |
922 | } | 935 | } |
923 | 936 | ||
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 6376ccf10fd4..3d4c9705041f 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h | |||
@@ -19,6 +19,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | |||
19 | int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep); | 19 | int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep); |
20 | void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, | 20 | void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, |
21 | int force, int can_sleep, int wait); | 21 | int force, int can_sleep, int wait); |
22 | void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); | ||
22 | int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); | 23 | int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); |
23 | int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); | 24 | int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); |
24 | void snd_usb_endpoint_free(struct list_head *head); | 25 | void snd_usb_endpoint_free(struct list_head *head); |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index fe56c9da38e9..298070e8f2d4 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -287,25 +287,32 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v | |||
287 | unsigned char buf[2]; | 287 | unsigned char buf[2]; |
288 | int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; | 288 | int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; |
289 | int timeout = 10; | 289 | int timeout = 10; |
290 | int err; | 290 | int idx = 0, err; |
291 | 291 | ||
292 | err = snd_usb_autoresume(cval->mixer->chip); | 292 | err = snd_usb_autoresume(cval->mixer->chip); |
293 | if (err < 0) | 293 | if (err < 0) |
294 | return -EIO; | 294 | return -EIO; |
295 | down_read(&chip->shutdown_rwsem); | ||
295 | while (timeout-- > 0) { | 296 | while (timeout-- > 0) { |
297 | if (chip->shutdown) | ||
298 | break; | ||
299 | idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); | ||
296 | if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, | 300 | if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, |
297 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 301 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
298 | validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), | 302 | validx, idx, buf, val_len) >= val_len) { |
299 | buf, val_len) >= val_len) { | ||
300 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); | 303 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); |
301 | snd_usb_autosuspend(cval->mixer->chip); | 304 | err = 0; |
302 | return 0; | 305 | goto out; |
303 | } | 306 | } |
304 | } | 307 | } |
305 | snd_usb_autosuspend(cval->mixer->chip); | ||
306 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 308 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
307 | request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); | 309 | request, validx, idx, cval->val_type); |
308 | return -EINVAL; | 310 | err = -EINVAL; |
311 | |||
312 | out: | ||
313 | up_read(&chip->shutdown_rwsem); | ||
314 | snd_usb_autosuspend(cval->mixer->chip); | ||
315 | return err; | ||
309 | } | 316 | } |
310 | 317 | ||
311 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | 318 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) |
@@ -313,7 +320,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v | |||
313 | struct snd_usb_audio *chip = cval->mixer->chip; | 320 | struct snd_usb_audio *chip = cval->mixer->chip; |
314 | unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ | 321 | unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ |
315 | unsigned char *val; | 322 | unsigned char *val; |
316 | int ret, size; | 323 | int idx = 0, ret, size; |
317 | __u8 bRequest; | 324 | __u8 bRequest; |
318 | 325 | ||
319 | if (request == UAC_GET_CUR) { | 326 | if (request == UAC_GET_CUR) { |
@@ -330,16 +337,22 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v | |||
330 | if (ret) | 337 | if (ret) |
331 | goto error; | 338 | goto error; |
332 | 339 | ||
333 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, | 340 | down_read(&chip->shutdown_rwsem); |
341 | if (chip->shutdown) | ||
342 | ret = -ENODEV; | ||
343 | else { | ||
344 | idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); | ||
345 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, | ||
334 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 346 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
335 | validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), | 347 | validx, idx, buf, size); |
336 | buf, size); | 348 | } |
349 | up_read(&chip->shutdown_rwsem); | ||
337 | snd_usb_autosuspend(chip); | 350 | snd_usb_autosuspend(chip); |
338 | 351 | ||
339 | if (ret < 0) { | 352 | if (ret < 0) { |
340 | error: | 353 | error: |
341 | snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 354 | snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
342 | request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); | 355 | request, validx, idx, cval->val_type); |
343 | return ret; | 356 | return ret; |
344 | } | 357 | } |
345 | 358 | ||
@@ -417,7 +430,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | |||
417 | { | 430 | { |
418 | struct snd_usb_audio *chip = cval->mixer->chip; | 431 | struct snd_usb_audio *chip = cval->mixer->chip; |
419 | unsigned char buf[2]; | 432 | unsigned char buf[2]; |
420 | int val_len, err, timeout = 10; | 433 | int idx = 0, val_len, err, timeout = 10; |
421 | 434 | ||
422 | if (cval->mixer->protocol == UAC_VERSION_1) { | 435 | if (cval->mixer->protocol == UAC_VERSION_1) { |
423 | val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; | 436 | val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; |
@@ -440,19 +453,27 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | |||
440 | err = snd_usb_autoresume(chip); | 453 | err = snd_usb_autoresume(chip); |
441 | if (err < 0) | 454 | if (err < 0) |
442 | return -EIO; | 455 | return -EIO; |
443 | while (timeout-- > 0) | 456 | down_read(&chip->shutdown_rwsem); |
457 | while (timeout-- > 0) { | ||
458 | if (chip->shutdown) | ||
459 | break; | ||
460 | idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); | ||
444 | if (snd_usb_ctl_msg(chip->dev, | 461 | if (snd_usb_ctl_msg(chip->dev, |
445 | usb_sndctrlpipe(chip->dev, 0), request, | 462 | usb_sndctrlpipe(chip->dev, 0), request, |
446 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | 463 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, |
447 | validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), | 464 | validx, idx, buf, val_len) >= 0) { |
448 | buf, val_len) >= 0) { | 465 | err = 0; |
449 | snd_usb_autosuspend(chip); | 466 | goto out; |
450 | return 0; | ||
451 | } | 467 | } |
452 | snd_usb_autosuspend(chip); | 468 | } |
453 | snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", | 469 | snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", |
454 | request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]); | 470 | request, validx, idx, cval->val_type, buf[0], buf[1]); |
455 | return -EINVAL; | 471 | err = -EINVAL; |
472 | |||
473 | out: | ||
474 | up_read(&chip->shutdown_rwsem); | ||
475 | snd_usb_autosuspend(chip); | ||
476 | return err; | ||
456 | } | 477 | } |
457 | 478 | ||
458 | static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) | 479 | static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) |
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 690000db0ec0..ae2b71435220 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -283,6 +283,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
283 | if (value > 1) | 283 | if (value > 1) |
284 | return -EINVAL; | 284 | return -EINVAL; |
285 | changed = value != mixer->audigy2nx_leds[index]; | 285 | changed = value != mixer->audigy2nx_leds[index]; |
286 | down_read(&mixer->chip->shutdown_rwsem); | ||
287 | if (mixer->chip->shutdown) { | ||
288 | err = -ENODEV; | ||
289 | goto out; | ||
290 | } | ||
286 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) | 291 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) |
287 | err = snd_usb_ctl_msg(mixer->chip->dev, | 292 | err = snd_usb_ctl_msg(mixer->chip->dev, |
288 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, | 293 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, |
@@ -299,6 +304,8 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
299 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, | 304 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, |
300 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | 305 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, |
301 | value, index + 2, NULL, 0); | 306 | value, index + 2, NULL, 0); |
307 | out: | ||
308 | up_read(&mixer->chip->shutdown_rwsem); | ||
302 | if (err < 0) | 309 | if (err < 0) |
303 | return err; | 310 | return err; |
304 | mixer->audigy2nx_leds[index] = value; | 311 | mixer->audigy2nx_leds[index] = value; |
@@ -392,11 +399,16 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, | |||
392 | 399 | ||
393 | for (i = 0; jacks[i].name; ++i) { | 400 | for (i = 0; jacks[i].name; ++i) { |
394 | snd_iprintf(buffer, "%s: ", jacks[i].name); | 401 | snd_iprintf(buffer, "%s: ", jacks[i].name); |
395 | err = snd_usb_ctl_msg(mixer->chip->dev, | 402 | down_read(&mixer->chip->shutdown_rwsem); |
403 | if (mixer->chip->shutdown) | ||
404 | err = 0; | ||
405 | else | ||
406 | err = snd_usb_ctl_msg(mixer->chip->dev, | ||
396 | usb_rcvctrlpipe(mixer->chip->dev, 0), | 407 | usb_rcvctrlpipe(mixer->chip->dev, 0), |
397 | UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | | 408 | UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | |
398 | USB_RECIP_INTERFACE, 0, | 409 | USB_RECIP_INTERFACE, 0, |
399 | jacks[i].unitid << 8, buf, 3); | 410 | jacks[i].unitid << 8, buf, 3); |
411 | up_read(&mixer->chip->shutdown_rwsem); | ||
400 | if (err == 3 && (buf[0] == 3 || buf[0] == 6)) | 412 | if (err == 3 && (buf[0] == 3 || buf[0] == 6)) |
401 | snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); | 413 | snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); |
402 | else | 414 | else |
@@ -426,10 +438,15 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, | |||
426 | else | 438 | else |
427 | new_status = old_status & ~0x02; | 439 | new_status = old_status & ~0x02; |
428 | changed = new_status != old_status; | 440 | changed = new_status != old_status; |
429 | err = snd_usb_ctl_msg(mixer->chip->dev, | 441 | down_read(&mixer->chip->shutdown_rwsem); |
442 | if (mixer->chip->shutdown) | ||
443 | err = -ENODEV; | ||
444 | else | ||
445 | err = snd_usb_ctl_msg(mixer->chip->dev, | ||
430 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, | 446 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, |
431 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | 447 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, |
432 | 50, 0, &new_status, 1); | 448 | 50, 0, &new_status, 1); |
449 | up_read(&mixer->chip->shutdown_rwsem); | ||
433 | if (err < 0) | 450 | if (err < 0) |
434 | return err; | 451 | return err; |
435 | mixer->xonar_u1_status = new_status; | 452 | mixer->xonar_u1_status = new_status; |
@@ -468,11 +485,17 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, | |||
468 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; | 485 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; |
469 | u16 wIndex = kcontrol->private_value & 0xffff; | 486 | u16 wIndex = kcontrol->private_value & 0xffff; |
470 | u8 tmp; | 487 | u8 tmp; |
488 | int ret; | ||
471 | 489 | ||
472 | int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, | 490 | down_read(&mixer->chip->shutdown_rwsem); |
491 | if (mixer->chip->shutdown) | ||
492 | ret = -ENODEV; | ||
493 | else | ||
494 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, | ||
473 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 495 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
474 | 0, cpu_to_le16(wIndex), | 496 | 0, cpu_to_le16(wIndex), |
475 | &tmp, sizeof(tmp), 1000); | 497 | &tmp, sizeof(tmp), 1000); |
498 | up_read(&mixer->chip->shutdown_rwsem); | ||
476 | 499 | ||
477 | if (ret < 0) { | 500 | if (ret < 0) { |
478 | snd_printk(KERN_ERR | 501 | snd_printk(KERN_ERR |
@@ -493,11 +516,17 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, | |||
493 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; | 516 | u8 bRequest = (kcontrol->private_value >> 16) & 0xff; |
494 | u16 wIndex = kcontrol->private_value & 0xffff; | 517 | u16 wIndex = kcontrol->private_value & 0xffff; |
495 | u16 wValue = ucontrol->value.integer.value[0]; | 518 | u16 wValue = ucontrol->value.integer.value[0]; |
519 | int ret; | ||
496 | 520 | ||
497 | int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, | 521 | down_read(&mixer->chip->shutdown_rwsem); |
522 | if (mixer->chip->shutdown) | ||
523 | ret = -ENODEV; | ||
524 | else | ||
525 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, | ||
498 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | 526 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
499 | cpu_to_le16(wValue), cpu_to_le16(wIndex), | 527 | cpu_to_le16(wValue), cpu_to_le16(wIndex), |
500 | NULL, 0, 1000); | 528 | NULL, 0, 1000); |
529 | up_read(&mixer->chip->shutdown_rwsem); | ||
501 | 530 | ||
502 | if (ret < 0) { | 531 | if (ret < 0) { |
503 | snd_printk(KERN_ERR | 532 | snd_printk(KERN_ERR |
@@ -656,11 +685,16 @@ static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, | |||
656 | return -EINVAL; | 685 | return -EINVAL; |
657 | 686 | ||
658 | 687 | ||
659 | err = snd_usb_ctl_msg(chip->dev, | 688 | down_read(&mixer->chip->shutdown_rwsem); |
689 | if (mixer->chip->shutdown) | ||
690 | err = -ENODEV; | ||
691 | else | ||
692 | err = snd_usb_ctl_msg(chip->dev, | ||
660 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, | 693 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, |
661 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 694 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
662 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | 695 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), |
663 | value, val_len); | 696 | value, val_len); |
697 | up_read(&mixer->chip->shutdown_rwsem); | ||
664 | if (err < 0) | 698 | if (err < 0) |
665 | return err; | 699 | return err; |
666 | 700 | ||
@@ -703,11 +737,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, | |||
703 | 737 | ||
704 | if (!pval->is_cached) { | 738 | if (!pval->is_cached) { |
705 | /* Read current value */ | 739 | /* Read current value */ |
706 | err = snd_usb_ctl_msg(chip->dev, | 740 | down_read(&mixer->chip->shutdown_rwsem); |
741 | if (mixer->chip->shutdown) | ||
742 | err = -ENODEV; | ||
743 | else | ||
744 | err = snd_usb_ctl_msg(chip->dev, | ||
707 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, | 745 | usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, |
708 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 746 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
709 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | 747 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), |
710 | value, val_len); | 748 | value, val_len); |
749 | up_read(&mixer->chip->shutdown_rwsem); | ||
711 | if (err < 0) | 750 | if (err < 0) |
712 | return err; | 751 | return err; |
713 | 752 | ||
@@ -719,11 +758,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, | |||
719 | if (cur_val != new_val) { | 758 | if (cur_val != new_val) { |
720 | value[0] = new_val; | 759 | value[0] = new_val; |
721 | value[1] = 0; | 760 | value[1] = 0; |
722 | err = snd_usb_ctl_msg(chip->dev, | 761 | down_read(&mixer->chip->shutdown_rwsem); |
762 | if (mixer->chip->shutdown) | ||
763 | err = -ENODEV; | ||
764 | else | ||
765 | err = snd_usb_ctl_msg(chip->dev, | ||
723 | usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, | 766 | usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, |
724 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | 767 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, |
725 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), | 768 | validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), |
726 | value, val_len); | 769 | value, val_len); |
770 | up_read(&mixer->chip->shutdown_rwsem); | ||
727 | if (err < 0) | 771 | if (err < 0) |
728 | return err; | 772 | return err; |
729 | 773 | ||
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 55e19e1b80ec..5c12a3fe8c3e 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -71,6 +71,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream | |||
71 | unsigned int hwptr_done; | 71 | unsigned int hwptr_done; |
72 | 72 | ||
73 | subs = (struct snd_usb_substream *)substream->runtime->private_data; | 73 | subs = (struct snd_usb_substream *)substream->runtime->private_data; |
74 | if (subs->stream->chip->shutdown) | ||
75 | return SNDRV_PCM_POS_XRUN; | ||
74 | spin_lock(&subs->lock); | 76 | spin_lock(&subs->lock); |
75 | hwptr_done = subs->hwptr_done; | 77 | hwptr_done = subs->hwptr_done; |
76 | substream->runtime->delay = snd_usb_pcm_delay(subs, | 78 | substream->runtime->delay = snd_usb_pcm_delay(subs, |
@@ -444,7 +446,6 @@ static int configure_endpoint(struct snd_usb_substream *subs) | |||
444 | { | 446 | { |
445 | int ret; | 447 | int ret; |
446 | 448 | ||
447 | mutex_lock(&subs->stream->chip->shutdown_mutex); | ||
448 | /* format changed */ | 449 | /* format changed */ |
449 | stop_endpoints(subs, 0, 0, 0); | 450 | stop_endpoints(subs, 0, 0, 0); |
450 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, | 451 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, |
@@ -455,7 +456,7 @@ static int configure_endpoint(struct snd_usb_substream *subs) | |||
455 | subs->cur_audiofmt, | 456 | subs->cur_audiofmt, |
456 | subs->sync_endpoint); | 457 | subs->sync_endpoint); |
457 | if (ret < 0) | 458 | if (ret < 0) |
458 | goto unlock; | 459 | return ret; |
459 | 460 | ||
460 | if (subs->sync_endpoint) | 461 | if (subs->sync_endpoint) |
461 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, | 462 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, |
@@ -465,9 +466,6 @@ static int configure_endpoint(struct snd_usb_substream *subs) | |||
465 | subs->cur_rate, | 466 | subs->cur_rate, |
466 | subs->cur_audiofmt, | 467 | subs->cur_audiofmt, |
467 | NULL); | 468 | NULL); |
468 | |||
469 | unlock: | ||
470 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
471 | return ret; | 469 | return ret; |
472 | } | 470 | } |
473 | 471 | ||
@@ -505,7 +503,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
505 | return -EINVAL; | 503 | return -EINVAL; |
506 | } | 504 | } |
507 | 505 | ||
508 | if ((ret = set_format(subs, fmt)) < 0) | 506 | down_read(&subs->stream->chip->shutdown_rwsem); |
507 | if (subs->stream->chip->shutdown) | ||
508 | ret = -ENODEV; | ||
509 | else | ||
510 | ret = set_format(subs, fmt); | ||
511 | up_read(&subs->stream->chip->shutdown_rwsem); | ||
512 | if (ret < 0) | ||
509 | return ret; | 513 | return ret; |
510 | 514 | ||
511 | subs->interface = fmt->iface; | 515 | subs->interface = fmt->iface; |
@@ -527,10 +531,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
527 | subs->cur_audiofmt = NULL; | 531 | subs->cur_audiofmt = NULL; |
528 | subs->cur_rate = 0; | 532 | subs->cur_rate = 0; |
529 | subs->period_bytes = 0; | 533 | subs->period_bytes = 0; |
530 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 534 | down_read(&subs->stream->chip->shutdown_rwsem); |
531 | stop_endpoints(subs, 0, 1, 1); | 535 | if (!subs->stream->chip->shutdown) { |
532 | deactivate_endpoints(subs); | 536 | stop_endpoints(subs, 0, 1, 1); |
533 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 537 | deactivate_endpoints(subs); |
538 | } | ||
539 | up_read(&subs->stream->chip->shutdown_rwsem); | ||
534 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 540 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
535 | } | 541 | } |
536 | 542 | ||
@@ -552,12 +558,22 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
552 | return -ENXIO; | 558 | return -ENXIO; |
553 | } | 559 | } |
554 | 560 | ||
555 | if (snd_BUG_ON(!subs->data_endpoint)) | 561 | down_read(&subs->stream->chip->shutdown_rwsem); |
556 | return -EIO; | 562 | if (subs->stream->chip->shutdown) { |
563 | ret = -ENODEV; | ||
564 | goto unlock; | ||
565 | } | ||
566 | if (snd_BUG_ON(!subs->data_endpoint)) { | ||
567 | ret = -EIO; | ||
568 | goto unlock; | ||
569 | } | ||
570 | |||
571 | snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); | ||
572 | snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); | ||
557 | 573 | ||
558 | ret = set_format(subs, subs->cur_audiofmt); | 574 | ret = set_format(subs, subs->cur_audiofmt); |
559 | if (ret < 0) | 575 | if (ret < 0) |
560 | return ret; | 576 | goto unlock; |
561 | 577 | ||
562 | iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); | 578 | iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); |
563 | alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; | 579 | alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; |
@@ -567,12 +583,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
567 | subs->cur_audiofmt, | 583 | subs->cur_audiofmt, |
568 | subs->cur_rate); | 584 | subs->cur_rate); |
569 | if (ret < 0) | 585 | if (ret < 0) |
570 | return ret; | 586 | goto unlock; |
571 | 587 | ||
572 | if (subs->need_setup_ep) { | 588 | if (subs->need_setup_ep) { |
573 | ret = configure_endpoint(subs); | 589 | ret = configure_endpoint(subs); |
574 | if (ret < 0) | 590 | if (ret < 0) |
575 | return ret; | 591 | goto unlock; |
576 | subs->need_setup_ep = false; | 592 | subs->need_setup_ep = false; |
577 | } | 593 | } |
578 | 594 | ||
@@ -592,9 +608,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
592 | /* for playback, submit the URBs now; otherwise, the first hwptr_done | 608 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
593 | * updates for all URBs would happen at the same time when starting */ | 609 | * updates for all URBs would happen at the same time when starting */ |
594 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) | 610 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) |
595 | return start_endpoints(subs, 1); | 611 | ret = start_endpoints(subs, 1); |
596 | 612 | ||
597 | return 0; | 613 | unlock: |
614 | up_read(&subs->stream->chip->shutdown_rwsem); | ||
615 | return ret; | ||
598 | } | 616 | } |
599 | 617 | ||
600 | static struct snd_pcm_hardware snd_usb_hardware = | 618 | static struct snd_pcm_hardware snd_usb_hardware = |
@@ -647,7 +665,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, | |||
647 | return 0; | 665 | return 0; |
648 | } | 666 | } |
649 | /* check whether the period time is >= the data packet interval */ | 667 | /* check whether the period time is >= the data packet interval */ |
650 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { | 668 | if (subs->speed != USB_SPEED_FULL) { |
651 | ptime = 125 * (1 << fp->datainterval); | 669 | ptime = 125 * (1 << fp->datainterval); |
652 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | 670 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { |
653 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | 671 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); |
@@ -925,7 +943,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
925 | return err; | 943 | return err; |
926 | 944 | ||
927 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 945 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
928 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 946 | if (subs->speed == USB_SPEED_FULL) |
929 | /* full speed devices have fixed data packet interval */ | 947 | /* full speed devices have fixed data packet interval */ |
930 | ptmin = 1000; | 948 | ptmin = 1000; |
931 | if (ptmin == 1000) | 949 | if (ptmin == 1000) |
diff --git a/sound/usb/proc.c b/sound/usb/proc.c index ebc1a5b5b3f1..d218f763501f 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c | |||
@@ -108,7 +108,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s | |||
108 | } | 108 | } |
109 | snd_iprintf(buffer, "\n"); | 109 | snd_iprintf(buffer, "\n"); |
110 | } | 110 | } |
111 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) | 111 | if (subs->speed != USB_SPEED_FULL) |
112 | snd_iprintf(buffer, " Data packet interval: %d us\n", | 112 | snd_iprintf(buffer, " Data packet interval: %d us\n", |
113 | 125 * (1 << fp->datainterval)); | 113 | 125 * (1 << fp->datainterval)); |
114 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); | 114 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); |
@@ -124,7 +124,7 @@ static void proc_dump_ep_status(struct snd_usb_substream *subs, | |||
124 | return; | 124 | return; |
125 | snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize); | 125 | snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize); |
126 | snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", | 126 | snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", |
127 | snd_usb_get_speed(subs->dev) == USB_SPEED_FULL | 127 | subs->speed == USB_SPEED_FULL |
128 | ? get_full_speed_hz(ep->freqm) | 128 | ? get_full_speed_hz(ep->freqm) |
129 | : get_high_speed_hz(ep->freqm), | 129 | : get_high_speed_hz(ep->freqm), |
130 | ep->freqm >> 16, ep->freqm & 0xffff); | 130 | ep->freqm >> 16, ep->freqm & 0xffff); |
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 083ed81160e5..1de0c8c002a8 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c | |||
@@ -90,6 +90,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, | |||
90 | subs->direction = stream; | 90 | subs->direction = stream; |
91 | subs->dev = as->chip->dev; | 91 | subs->dev = as->chip->dev; |
92 | subs->txfr_quirk = as->chip->txfr_quirk; | 92 | subs->txfr_quirk = as->chip->txfr_quirk; |
93 | subs->speed = snd_usb_get_speed(subs->dev); | ||
93 | 94 | ||
94 | snd_usb_set_pcm_ops(as->pcm, stream); | 95 | snd_usb_set_pcm_ops(as->pcm, stream); |
95 | 96 | ||
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b8233ebe250f..ef42797f56fb 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -37,7 +37,7 @@ struct snd_usb_audio { | |||
37 | struct usb_interface *pm_intf; | 37 | struct usb_interface *pm_intf; |
38 | u32 usb_id; | 38 | u32 usb_id; |
39 | struct mutex mutex; | 39 | struct mutex mutex; |
40 | struct mutex shutdown_mutex; | 40 | struct rw_semaphore shutdown_rwsem; |
41 | unsigned int shutdown:1; | 41 | unsigned int shutdown:1; |
42 | unsigned int probing:1; | 42 | unsigned int probing:1; |
43 | unsigned int autosuspended:1; | 43 | unsigned int autosuspended:1; |