diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-10-30 06:08:25 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-10-30 06:08:25 -0400 |
commit | a5d00dc3a4b65ed38249f3225e453944c633747b (patch) | |
tree | 6249ca5a5f13059f42890525a9ea7133778f3891 /sound/usb | |
parent | 1a8506d4402b6e96c2ed778dc7ccbb48d1e02fce (diff) | |
parent | 0914f7961babbf28aaa2f19b453951fb4841c03f (diff) |
Merge branch 'for-linus' into for-next
... for migrating the core changes for USB-audio disconnection fixes
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 12 | ||||
-rw-r--r-- | sound/usb/card.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 | 53 | ||||
-rw-r--r-- | sound/usb/proc.c | 4 | ||||
-rw-r--r-- | sound/usb/stream.c | 1 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 2 |
8 files changed, 141 insertions, 55 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 561bb74fd364..282f0fc9fed1 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; |
@@ -560,7 +560,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
560 | 560 | ||
561 | card = chip->card; | 561 | card = chip->card; |
562 | mutex_lock(®ister_mutex); | 562 | mutex_lock(®ister_mutex); |
563 | mutex_lock(&chip->shutdown_mutex); | 563 | down_write(&chip->shutdown_rwsem); |
564 | chip->shutdown = 1; | 564 | chip->shutdown = 1; |
565 | chip->num_interfaces--; | 565 | chip->num_interfaces--; |
566 | if (chip->num_interfaces <= 0) { | 566 | if (chip->num_interfaces <= 0) { |
@@ -582,11 +582,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
582 | snd_usb_mixer_disconnect(p); | 582 | snd_usb_mixer_disconnect(p); |
583 | } | 583 | } |
584 | usb_chip[chip->index] = NULL; | 584 | usb_chip[chip->index] = NULL; |
585 | mutex_unlock(&chip->shutdown_mutex); | 585 | up_write(&chip->shutdown_rwsem); |
586 | mutex_unlock(®ister_mutex); | 586 | mutex_unlock(®ister_mutex); |
587 | snd_card_free_when_closed(card); | 587 | snd_card_free_when_closed(card); |
588 | } else { | 588 | } else { |
589 | mutex_unlock(&chip->shutdown_mutex); | 589 | up_write(&chip->shutdown_rwsem); |
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/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 f77b87ad0256..8ca6edf29fee 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, |
@@ -441,7 +443,6 @@ static int configure_endpoint(struct snd_usb_substream *subs) | |||
441 | { | 443 | { |
442 | int ret; | 444 | int ret; |
443 | 445 | ||
444 | mutex_lock(&subs->stream->chip->shutdown_mutex); | ||
445 | /* format changed */ | 446 | /* format changed */ |
446 | stop_endpoints(subs, 0, 0, 0); | 447 | stop_endpoints(subs, 0, 0, 0); |
447 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, | 448 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, |
@@ -452,7 +453,7 @@ static int configure_endpoint(struct snd_usb_substream *subs) | |||
452 | subs->cur_audiofmt, | 453 | subs->cur_audiofmt, |
453 | subs->sync_endpoint); | 454 | subs->sync_endpoint); |
454 | if (ret < 0) | 455 | if (ret < 0) |
455 | goto unlock; | 456 | return ret; |
456 | 457 | ||
457 | if (subs->sync_endpoint) | 458 | if (subs->sync_endpoint) |
458 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, | 459 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, |
@@ -462,9 +463,6 @@ static int configure_endpoint(struct snd_usb_substream *subs) | |||
462 | subs->cur_rate, | 463 | subs->cur_rate, |
463 | subs->cur_audiofmt, | 464 | subs->cur_audiofmt, |
464 | NULL); | 465 | NULL); |
465 | |||
466 | unlock: | ||
467 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
468 | return ret; | 466 | return ret; |
469 | } | 467 | } |
470 | 468 | ||
@@ -502,7 +500,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
502 | return -EINVAL; | 500 | return -EINVAL; |
503 | } | 501 | } |
504 | 502 | ||
505 | if ((ret = set_format(subs, fmt)) < 0) | 503 | down_read(&subs->stream->chip->shutdown_rwsem); |
504 | if (subs->stream->chip->shutdown) | ||
505 | ret = -ENODEV; | ||
506 | else | ||
507 | ret = set_format(subs, fmt); | ||
508 | up_read(&subs->stream->chip->shutdown_rwsem); | ||
509 | if (ret < 0) | ||
506 | return ret; | 510 | return ret; |
507 | 511 | ||
508 | subs->interface = fmt->iface; | 512 | subs->interface = fmt->iface; |
@@ -524,10 +528,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
524 | subs->cur_audiofmt = NULL; | 528 | subs->cur_audiofmt = NULL; |
525 | subs->cur_rate = 0; | 529 | subs->cur_rate = 0; |
526 | subs->period_bytes = 0; | 530 | subs->period_bytes = 0; |
527 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 531 | down_read(&subs->stream->chip->shutdown_rwsem); |
528 | stop_endpoints(subs, 0, 1, 1); | 532 | if (!subs->stream->chip->shutdown) { |
529 | deactivate_endpoints(subs); | 533 | stop_endpoints(subs, 0, 1, 1); |
530 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 534 | deactivate_endpoints(subs); |
535 | } | ||
536 | up_read(&subs->stream->chip->shutdown_rwsem); | ||
531 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 537 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
532 | } | 538 | } |
533 | 539 | ||
@@ -549,12 +555,19 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
549 | return -ENXIO; | 555 | return -ENXIO; |
550 | } | 556 | } |
551 | 557 | ||
552 | if (snd_BUG_ON(!subs->data_endpoint)) | 558 | down_read(&subs->stream->chip->shutdown_rwsem); |
553 | return -EIO; | 559 | if (subs->stream->chip->shutdown) { |
560 | ret = -ENODEV; | ||
561 | goto unlock; | ||
562 | } | ||
563 | if (snd_BUG_ON(!subs->data_endpoint)) { | ||
564 | ret = -EIO; | ||
565 | goto unlock; | ||
566 | } | ||
554 | 567 | ||
555 | ret = set_format(subs, subs->cur_audiofmt); | 568 | ret = set_format(subs, subs->cur_audiofmt); |
556 | if (ret < 0) | 569 | if (ret < 0) |
557 | return ret; | 570 | goto unlock; |
558 | 571 | ||
559 | iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); | 572 | iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); |
560 | alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; | 573 | alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; |
@@ -564,12 +577,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
564 | subs->cur_audiofmt, | 577 | subs->cur_audiofmt, |
565 | subs->cur_rate); | 578 | subs->cur_rate); |
566 | if (ret < 0) | 579 | if (ret < 0) |
567 | return ret; | 580 | goto unlock; |
568 | 581 | ||
569 | if (subs->need_setup_ep) { | 582 | if (subs->need_setup_ep) { |
570 | ret = configure_endpoint(subs); | 583 | ret = configure_endpoint(subs); |
571 | if (ret < 0) | 584 | if (ret < 0) |
572 | return ret; | 585 | goto unlock; |
573 | subs->need_setup_ep = false; | 586 | subs->need_setup_ep = false; |
574 | } | 587 | } |
575 | 588 | ||
@@ -589,9 +602,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
589 | /* for playback, submit the URBs now; otherwise, the first hwptr_done | 602 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
590 | * updates for all URBs would happen at the same time when starting */ | 603 | * updates for all URBs would happen at the same time when starting */ |
591 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) | 604 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) |
592 | return start_endpoints(subs, 1); | 605 | ret = start_endpoints(subs, 1); |
593 | 606 | ||
594 | return 0; | 607 | unlock: |
608 | up_read(&subs->stream->chip->shutdown_rwsem); | ||
609 | return ret; | ||
595 | } | 610 | } |
596 | 611 | ||
597 | static struct snd_pcm_hardware snd_usb_hardware = | 612 | static struct snd_pcm_hardware snd_usb_hardware = |
@@ -644,7 +659,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, | |||
644 | return 0; | 659 | return 0; |
645 | } | 660 | } |
646 | /* check whether the period time is >= the data packet interval */ | 661 | /* check whether the period time is >= the data packet interval */ |
647 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { | 662 | if (subs->speed != USB_SPEED_FULL) { |
648 | ptime = 125 * (1 << fp->datainterval); | 663 | ptime = 125 * (1 << fp->datainterval); |
649 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | 664 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { |
650 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | 665 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); |
@@ -922,7 +937,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
922 | return err; | 937 | return err; |
923 | 938 | ||
924 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 939 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
925 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 940 | if (subs->speed == USB_SPEED_FULL) |
926 | /* full speed devices have fixed data packet interval */ | 941 | /* full speed devices have fixed data packet interval */ |
927 | ptmin = 1000; | 942 | ptmin = 1000; |
928 | if (ptmin == 1000) | 943 | 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; |