diff options
| -rw-r--r-- | include/sound/core.h | 3 | ||||
| -rw-r--r-- | sound/core/compress_offload.c | 9 | ||||
| -rw-r--r-- | sound/core/control.c | 5 | ||||
| -rw-r--r-- | sound/core/hwdep.c | 12 | ||||
| -rw-r--r-- | sound/core/init.c | 50 | ||||
| -rw-r--r-- | sound/core/oss/mixer_oss.c | 10 | ||||
| -rw-r--r-- | sound/core/oss/pcm_oss.c | 6 | ||||
| -rw-r--r-- | sound/core/pcm.c | 13 | ||||
| -rw-r--r-- | sound/core/pcm_native.c | 33 | ||||
| -rw-r--r-- | sound/core/rawmidi.c | 26 | ||||
| -rw-r--r-- | sound/core/sound.c | 11 | ||||
| -rw-r--r-- | sound/core/sound_oss.c | 10 | ||||
| -rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 2 | ||||
| -rw-r--r-- | sound/pci/ice1712/ice1724.c | 7 | ||||
| -rw-r--r-- | sound/soc/omap/omap-dmic.c | 4 | ||||
| -rw-r--r-- | sound/soc/omap/zoom2.c | 5 | ||||
| -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 |
24 files changed, 303 insertions, 99 deletions
diff --git a/include/sound/core.h b/include/sound/core.h index bc056687f647..93896ad1fcdd 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
| @@ -132,6 +132,7 @@ struct snd_card { | |||
| 132 | int shutdown; /* this card is going down */ | 132 | int shutdown; /* this card is going down */ |
| 133 | int free_on_last_close; /* free in context of file_release */ | 133 | int free_on_last_close; /* free in context of file_release */ |
| 134 | wait_queue_head_t shutdown_sleep; | 134 | wait_queue_head_t shutdown_sleep; |
| 135 | atomic_t refcount; /* refcount for disconnection */ | ||
| 135 | struct device *dev; /* device assigned to this card */ | 136 | struct device *dev; /* device assigned to this card */ |
| 136 | struct device *card_dev; /* cardX object for sysfs */ | 137 | struct device *card_dev; /* cardX object for sysfs */ |
| 137 | 138 | ||
| @@ -189,6 +190,7 @@ struct snd_minor { | |||
| 189 | const struct file_operations *f_ops; /* file operations */ | 190 | const struct file_operations *f_ops; /* file operations */ |
| 190 | void *private_data; /* private data for f_ops->open */ | 191 | void *private_data; /* private data for f_ops->open */ |
| 191 | struct device *dev; /* device for sysfs */ | 192 | struct device *dev; /* device for sysfs */ |
| 193 | struct snd_card *card_ptr; /* assigned card instance */ | ||
| 192 | }; | 194 | }; |
| 193 | 195 | ||
| 194 | /* return a device pointer linked to each sound device as a parent */ | 196 | /* return a device pointer linked to each sound device as a parent */ |
| @@ -295,6 +297,7 @@ int snd_card_info_done(void); | |||
| 295 | int snd_component_add(struct snd_card *card, const char *component); | 297 | int snd_component_add(struct snd_card *card, const char *component); |
| 296 | int snd_card_file_add(struct snd_card *card, struct file *file); | 298 | int snd_card_file_add(struct snd_card *card, struct file *file); |
| 297 | int snd_card_file_remove(struct snd_card *card, struct file *file); | 299 | int snd_card_file_remove(struct snd_card *card, struct file *file); |
| 300 | void snd_card_unref(struct snd_card *card); | ||
| 298 | 301 | ||
| 299 | #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) | 302 | #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) |
| 300 | 303 | ||
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index c40ae573346d..ad11dc994792 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c | |||
| @@ -100,12 +100,15 @@ static int snd_compr_open(struct inode *inode, struct file *f) | |||
| 100 | 100 | ||
| 101 | if (dirn != compr->direction) { | 101 | if (dirn != compr->direction) { |
| 102 | pr_err("this device doesn't support this direction\n"); | 102 | pr_err("this device doesn't support this direction\n"); |
| 103 | snd_card_unref(compr->card); | ||
| 103 | return -EINVAL; | 104 | return -EINVAL; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 107 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
| 107 | if (!data) | 108 | if (!data) { |
| 109 | snd_card_unref(compr->card); | ||
| 108 | return -ENOMEM; | 110 | return -ENOMEM; |
| 111 | } | ||
| 109 | data->stream.ops = compr->ops; | 112 | data->stream.ops = compr->ops; |
| 110 | data->stream.direction = dirn; | 113 | data->stream.direction = dirn; |
| 111 | data->stream.private_data = compr->private_data; | 114 | data->stream.private_data = compr->private_data; |
| @@ -113,6 +116,7 @@ static int snd_compr_open(struct inode *inode, struct file *f) | |||
| 113 | runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); | 116 | runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); |
| 114 | if (!runtime) { | 117 | if (!runtime) { |
| 115 | kfree(data); | 118 | kfree(data); |
| 119 | snd_card_unref(compr->card); | ||
| 116 | return -ENOMEM; | 120 | return -ENOMEM; |
| 117 | } | 121 | } |
| 118 | runtime->state = SNDRV_PCM_STATE_OPEN; | 122 | runtime->state = SNDRV_PCM_STATE_OPEN; |
| @@ -126,7 +130,8 @@ static int snd_compr_open(struct inode *inode, struct file *f) | |||
| 126 | kfree(runtime); | 130 | kfree(runtime); |
| 127 | kfree(data); | 131 | kfree(data); |
| 128 | } | 132 | } |
| 129 | return ret; | 133 | snd_card_unref(compr->card); |
| 134 | return 0; | ||
| 130 | } | 135 | } |
| 131 | 136 | ||
| 132 | static int snd_compr_free(struct inode *inode, struct file *f) | 137 | static int snd_compr_free(struct inode *inode, struct file *f) |
diff --git a/sound/core/control.c b/sound/core/control.c index 7e86a5b9f3b5..8c7c2c9bba61 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
| @@ -86,6 +86,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) | |||
| 86 | write_lock_irqsave(&card->ctl_files_rwlock, flags); | 86 | write_lock_irqsave(&card->ctl_files_rwlock, flags); |
| 87 | list_add_tail(&ctl->list, &card->ctl_files); | 87 | list_add_tail(&ctl->list, &card->ctl_files); |
| 88 | write_unlock_irqrestore(&card->ctl_files_rwlock, flags); | 88 | write_unlock_irqrestore(&card->ctl_files_rwlock, flags); |
| 89 | snd_card_unref(card); | ||
| 89 | return 0; | 90 | return 0; |
| 90 | 91 | ||
| 91 | __error: | 92 | __error: |
| @@ -93,6 +94,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) | |||
| 93 | __error2: | 94 | __error2: |
| 94 | snd_card_file_remove(card, file); | 95 | snd_card_file_remove(card, file); |
| 95 | __error1: | 96 | __error1: |
| 97 | if (card) | ||
| 98 | snd_card_unref(card); | ||
| 96 | return err; | 99 | return err; |
| 97 | } | 100 | } |
| 98 | 101 | ||
| @@ -1434,6 +1437,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, | |||
| 1434 | spin_unlock_irq(&ctl->read_lock); | 1437 | spin_unlock_irq(&ctl->read_lock); |
| 1435 | schedule(); | 1438 | schedule(); |
| 1436 | remove_wait_queue(&ctl->change_sleep, &wait); | 1439 | remove_wait_queue(&ctl->change_sleep, &wait); |
| 1440 | if (ctl->card->shutdown) | ||
| 1441 | return -ENODEV; | ||
| 1437 | if (signal_pending(current)) | 1442 | if (signal_pending(current)) |
| 1438 | return -ERESTARTSYS; | 1443 | return -ERESTARTSYS; |
| 1439 | spin_lock_irq(&ctl->read_lock); | 1444 | spin_lock_irq(&ctl->read_lock); |
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 75ea16f35b1a..3f7f6628cf7b 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
| @@ -100,8 +100,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) | |||
| 100 | if (hw == NULL) | 100 | if (hw == NULL) |
| 101 | return -ENODEV; | 101 | return -ENODEV; |
| 102 | 102 | ||
| 103 | if (!try_module_get(hw->card->module)) | 103 | if (!try_module_get(hw->card->module)) { |
| 104 | snd_card_unref(hw->card); | ||
| 104 | return -EFAULT; | 105 | return -EFAULT; |
| 106 | } | ||
| 105 | 107 | ||
| 106 | init_waitqueue_entry(&wait, current); | 108 | init_waitqueue_entry(&wait, current); |
| 107 | add_wait_queue(&hw->open_wait, &wait); | 109 | add_wait_queue(&hw->open_wait, &wait); |
| @@ -129,6 +131,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) | |||
| 129 | mutex_unlock(&hw->open_mutex); | 131 | mutex_unlock(&hw->open_mutex); |
| 130 | schedule(); | 132 | schedule(); |
| 131 | mutex_lock(&hw->open_mutex); | 133 | mutex_lock(&hw->open_mutex); |
| 134 | if (hw->card->shutdown) { | ||
| 135 | err = -ENODEV; | ||
| 136 | break; | ||
| 137 | } | ||
| 132 | if (signal_pending(current)) { | 138 | if (signal_pending(current)) { |
| 133 | err = -ERESTARTSYS; | 139 | err = -ERESTARTSYS; |
| 134 | break; | 140 | break; |
| @@ -148,6 +154,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) | |||
| 148 | mutex_unlock(&hw->open_mutex); | 154 | mutex_unlock(&hw->open_mutex); |
| 149 | if (err < 0) | 155 | if (err < 0) |
| 150 | module_put(hw->card->module); | 156 | module_put(hw->card->module); |
| 157 | snd_card_unref(hw->card); | ||
| 151 | return err; | 158 | return err; |
| 152 | } | 159 | } |
| 153 | 160 | ||
| @@ -459,12 +466,15 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) | |||
| 459 | mutex_unlock(®ister_mutex); | 466 | mutex_unlock(®ister_mutex); |
| 460 | return -EINVAL; | 467 | return -EINVAL; |
| 461 | } | 468 | } |
| 469 | mutex_lock(&hwdep->open_mutex); | ||
| 470 | wake_up(&hwdep->open_wait); | ||
| 462 | #ifdef CONFIG_SND_OSSEMUL | 471 | #ifdef CONFIG_SND_OSSEMUL |
| 463 | if (hwdep->ossreg) | 472 | if (hwdep->ossreg) |
| 464 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); | 473 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); |
| 465 | #endif | 474 | #endif |
| 466 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); | 475 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); |
| 467 | list_del_init(&hwdep->list); | 476 | list_del_init(&hwdep->list); |
| 477 | mutex_unlock(&hwdep->open_mutex); | ||
| 468 | mutex_unlock(®ister_mutex); | 478 | mutex_unlock(®ister_mutex); |
| 469 | return 0; | 479 | return 0; |
| 470 | } | 480 | } |
diff --git a/sound/core/init.c b/sound/core/init.c index d8ec849af128..7b012d15c2cf 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
| @@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid, | |||
| 213 | spin_lock_init(&card->files_lock); | 213 | spin_lock_init(&card->files_lock); |
| 214 | INIT_LIST_HEAD(&card->files_list); | 214 | INIT_LIST_HEAD(&card->files_list); |
| 215 | init_waitqueue_head(&card->shutdown_sleep); | 215 | init_waitqueue_head(&card->shutdown_sleep); |
| 216 | atomic_set(&card->refcount, 0); | ||
| 216 | #ifdef CONFIG_PM | 217 | #ifdef CONFIG_PM |
| 217 | mutex_init(&card->power_lock); | 218 | mutex_init(&card->power_lock); |
| 218 | init_waitqueue_head(&card->power_sleep); | 219 | init_waitqueue_head(&card->power_sleep); |
| @@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card) | |||
| 446 | return 0; | 447 | return 0; |
| 447 | } | 448 | } |
| 448 | 449 | ||
| 450 | /** | ||
| 451 | * snd_card_unref - release the reference counter | ||
| 452 | * @card: the card instance | ||
| 453 | * | ||
| 454 | * Decrements the reference counter. When it reaches to zero, wake up | ||
| 455 | * the sleeper and call the destructor if needed. | ||
| 456 | */ | ||
| 457 | void snd_card_unref(struct snd_card *card) | ||
| 458 | { | ||
| 459 | if (atomic_dec_and_test(&card->refcount)) { | ||
| 460 | wake_up(&card->shutdown_sleep); | ||
| 461 | if (card->free_on_last_close) | ||
| 462 | snd_card_do_free(card); | ||
| 463 | } | ||
| 464 | } | ||
| 465 | EXPORT_SYMBOL(snd_card_unref); | ||
| 466 | |||
| 449 | int snd_card_free_when_closed(struct snd_card *card) | 467 | int snd_card_free_when_closed(struct snd_card *card) |
| 450 | { | 468 | { |
| 451 | int free_now = 0; | 469 | int ret; |
| 452 | int ret = snd_card_disconnect(card); | ||
| 453 | if (ret) | ||
| 454 | return ret; | ||
| 455 | 470 | ||
| 456 | spin_lock(&card->files_lock); | 471 | atomic_inc(&card->refcount); |
| 457 | if (list_empty(&card->files_list)) | 472 | ret = snd_card_disconnect(card); |
| 458 | free_now = 1; | 473 | if (ret) { |
| 459 | else | 474 | atomic_dec(&card->refcount); |
| 460 | card->free_on_last_close = 1; | 475 | return ret; |
| 461 | spin_unlock(&card->files_lock); | 476 | } |
| 462 | 477 | ||
| 463 | if (free_now) | 478 | card->free_on_last_close = 1; |
| 479 | if (atomic_dec_and_test(&card->refcount)) | ||
| 464 | snd_card_do_free(card); | 480 | snd_card_do_free(card); |
| 465 | return 0; | 481 | return 0; |
| 466 | } | 482 | } |
| @@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card) | |||
| 474 | return ret; | 490 | return ret; |
| 475 | 491 | ||
| 476 | /* wait, until all devices are ready for the free operation */ | 492 | /* wait, until all devices are ready for the free operation */ |
| 477 | wait_event(card->shutdown_sleep, list_empty(&card->files_list)); | 493 | wait_event(card->shutdown_sleep, !atomic_read(&card->refcount)); |
| 478 | snd_card_do_free(card); | 494 | snd_card_do_free(card); |
| 479 | return 0; | 495 | return 0; |
| 480 | } | 496 | } |
| @@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file) | |||
| 886 | return -ENODEV; | 902 | return -ENODEV; |
| 887 | } | 903 | } |
| 888 | list_add(&mfile->list, &card->files_list); | 904 | list_add(&mfile->list, &card->files_list); |
| 905 | atomic_inc(&card->refcount); | ||
| 889 | spin_unlock(&card->files_lock); | 906 | spin_unlock(&card->files_lock); |
| 890 | return 0; | 907 | return 0; |
| 891 | } | 908 | } |
| @@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add); | |||
| 908 | int snd_card_file_remove(struct snd_card *card, struct file *file) | 925 | int snd_card_file_remove(struct snd_card *card, struct file *file) |
| 909 | { | 926 | { |
| 910 | struct snd_monitor_file *mfile, *found = NULL; | 927 | struct snd_monitor_file *mfile, *found = NULL; |
| 911 | int last_close = 0; | ||
| 912 | 928 | ||
| 913 | spin_lock(&card->files_lock); | 929 | spin_lock(&card->files_lock); |
| 914 | list_for_each_entry(mfile, &card->files_list, list) { | 930 | list_for_each_entry(mfile, &card->files_list, list) { |
| @@ -923,19 +939,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
| 923 | break; | 939 | break; |
| 924 | } | 940 | } |
| 925 | } | 941 | } |
| 926 | if (list_empty(&card->files_list)) | ||
| 927 | last_close = 1; | ||
| 928 | spin_unlock(&card->files_lock); | 942 | spin_unlock(&card->files_lock); |
| 929 | if (last_close) { | ||
| 930 | wake_up(&card->shutdown_sleep); | ||
| 931 | if (card->free_on_last_close) | ||
| 932 | snd_card_do_free(card); | ||
| 933 | } | ||
| 934 | if (!found) { | 943 | if (!found) { |
| 935 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); | 944 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); |
| 936 | return -ENOENT; | 945 | return -ENOENT; |
| 937 | } | 946 | } |
| 938 | kfree(found); | 947 | kfree(found); |
| 948 | snd_card_unref(card); | ||
| 939 | return 0; | 949 | return 0; |
| 940 | } | 950 | } |
| 941 | 951 | ||
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 29f6ded02555..a9a2e63c0222 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
| @@ -52,14 +52,19 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) | |||
| 52 | SNDRV_OSS_DEVICE_TYPE_MIXER); | 52 | SNDRV_OSS_DEVICE_TYPE_MIXER); |
| 53 | if (card == NULL) | 53 | if (card == NULL) |
| 54 | return -ENODEV; | 54 | return -ENODEV; |
| 55 | if (card->mixer_oss == NULL) | 55 | if (card->mixer_oss == NULL) { |
| 56 | snd_card_unref(card); | ||
| 56 | return -ENODEV; | 57 | return -ENODEV; |
| 58 | } | ||
| 57 | err = snd_card_file_add(card, file); | 59 | err = snd_card_file_add(card, file); |
| 58 | if (err < 0) | 60 | if (err < 0) { |
| 61 | snd_card_unref(card); | ||
| 59 | return err; | 62 | return err; |
| 63 | } | ||
| 60 | fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL); | 64 | fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL); |
| 61 | if (fmixer == NULL) { | 65 | if (fmixer == NULL) { |
| 62 | snd_card_file_remove(card, file); | 66 | snd_card_file_remove(card, file); |
| 67 | snd_card_unref(card); | ||
| 63 | return -ENOMEM; | 68 | return -ENOMEM; |
| 64 | } | 69 | } |
| 65 | fmixer->card = card; | 70 | fmixer->card = card; |
| @@ -68,6 +73,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) | |||
| 68 | if (!try_module_get(card->module)) { | 73 | if (!try_module_get(card->module)) { |
| 69 | kfree(fmixer); | 74 | kfree(fmixer); |
| 70 | snd_card_file_remove(card, file); | 75 | snd_card_file_remove(card, file); |
| 76 | snd_card_unref(card); | ||
| 71 | return -EFAULT; | 77 | return -EFAULT; |
| 72 | } | 78 | } |
| 73 | return 0; | 79 | return 0; |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 08fde0060fd9..f337b66a020b 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
| @@ -2441,6 +2441,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) | |||
| 2441 | mutex_unlock(&pcm->open_mutex); | 2441 | mutex_unlock(&pcm->open_mutex); |
| 2442 | schedule(); | 2442 | schedule(); |
| 2443 | mutex_lock(&pcm->open_mutex); | 2443 | mutex_lock(&pcm->open_mutex); |
| 2444 | if (pcm->card->shutdown) { | ||
| 2445 | err = -ENODEV; | ||
| 2446 | break; | ||
| 2447 | } | ||
| 2444 | if (signal_pending(current)) { | 2448 | if (signal_pending(current)) { |
| 2445 | err = -ERESTARTSYS; | 2449 | err = -ERESTARTSYS; |
| 2446 | break; | 2450 | break; |
| @@ -2457,6 +2461,8 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) | |||
| 2457 | __error2: | 2461 | __error2: |
| 2458 | snd_card_file_remove(pcm->card, file); | 2462 | snd_card_file_remove(pcm->card, file); |
| 2459 | __error1: | 2463 | __error1: |
| 2464 | if (pcm) | ||
| 2465 | snd_card_unref(pcm->card); | ||
| 2460 | return err; | 2466 | return err; |
| 2461 | } | 2467 | } |
| 2462 | 2468 | ||
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index f2991940b271..030102caeee9 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
| @@ -1086,11 +1086,19 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
| 1086 | if (list_empty(&pcm->list)) | 1086 | if (list_empty(&pcm->list)) |
| 1087 | goto unlock; | 1087 | goto unlock; |
| 1088 | 1088 | ||
| 1089 | mutex_lock(&pcm->open_mutex); | ||
| 1090 | wake_up(&pcm->open_wait); | ||
| 1089 | list_del_init(&pcm->list); | 1091 | list_del_init(&pcm->list); |
| 1090 | for (cidx = 0; cidx < 2; cidx++) | 1092 | for (cidx = 0; cidx < 2; cidx++) |
| 1091 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 1093 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { |
| 1092 | if (substream->runtime) | 1094 | snd_pcm_stream_lock_irq(substream); |
| 1095 | if (substream->runtime) { | ||
| 1093 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; | 1096 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; |
| 1097 | wake_up(&substream->runtime->sleep); | ||
| 1098 | wake_up(&substream->runtime->tsleep); | ||
| 1099 | } | ||
| 1100 | snd_pcm_stream_unlock_irq(substream); | ||
| 1101 | } | ||
| 1094 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | 1102 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { |
| 1095 | notify->n_disconnect(pcm); | 1103 | notify->n_disconnect(pcm); |
| 1096 | } | 1104 | } |
| @@ -1110,6 +1118,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
| 1110 | pcm->streams[cidx].chmap_kctl = NULL; | 1118 | pcm->streams[cidx].chmap_kctl = NULL; |
| 1111 | } | 1119 | } |
| 1112 | } | 1120 | } |
| 1121 | mutex_unlock(&pcm->open_mutex); | ||
| 1113 | unlock: | 1122 | unlock: |
| 1114 | mutex_unlock(®ister_mutex); | 1123 | mutex_unlock(®ister_mutex); |
| 1115 | return 0; | 1124 | return 0; |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5e12e5bacbba..6e8872de5ba0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
| @@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) | |||
| 369 | return usecs; | 369 | return usecs; |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state) | ||
| 373 | { | ||
| 374 | snd_pcm_stream_lock_irq(substream); | ||
| 375 | if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) | ||
| 376 | substream->runtime->status->state = state; | ||
| 377 | snd_pcm_stream_unlock_irq(substream); | ||
| 378 | } | ||
| 379 | |||
| 372 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | 380 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, |
| 373 | struct snd_pcm_hw_params *params) | 381 | struct snd_pcm_hw_params *params) |
| 374 | { | 382 | { |
| @@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 452 | runtime->boundary *= 2; | 460 | runtime->boundary *= 2; |
| 453 | 461 | ||
| 454 | snd_pcm_timer_resolution_change(substream); | 462 | snd_pcm_timer_resolution_change(substream); |
| 455 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | 463 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP); |
| 456 | 464 | ||
| 457 | if (pm_qos_request_active(&substream->latency_pm_qos_req)) | 465 | if (pm_qos_request_active(&substream->latency_pm_qos_req)) |
| 458 | pm_qos_remove_request(&substream->latency_pm_qos_req); | 466 | pm_qos_remove_request(&substream->latency_pm_qos_req); |
| @@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 464 | /* hardware might be unusable from this time, | 472 | /* hardware might be unusable from this time, |
| 465 | so we force application to retry to set | 473 | so we force application to retry to set |
| 466 | the correct hardware parameter settings */ | 474 | the correct hardware parameter settings */ |
| 467 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 475 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); |
| 468 | if (substream->ops->hw_free != NULL) | 476 | if (substream->ops->hw_free != NULL) |
| 469 | substream->ops->hw_free(substream); | 477 | substream->ops->hw_free(substream); |
| 470 | return err; | 478 | return err; |
| @@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) | |||
| 512 | return -EBADFD; | 520 | return -EBADFD; |
| 513 | if (substream->ops->hw_free) | 521 | if (substream->ops->hw_free) |
| 514 | result = substream->ops->hw_free(substream); | 522 | result = substream->ops->hw_free(substream); |
| 515 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 523 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); |
| 516 | pm_qos_remove_request(&substream->latency_pm_qos_req); | 524 | pm_qos_remove_request(&substream->latency_pm_qos_req); |
| 517 | return result; | 525 | return result; |
| 518 | } | 526 | } |
| @@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) | |||
| 1320 | { | 1328 | { |
| 1321 | struct snd_pcm_runtime *runtime = substream->runtime; | 1329 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1322 | runtime->control->appl_ptr = runtime->status->hw_ptr; | 1330 | runtime->control->appl_ptr = runtime->status->hw_ptr; |
| 1323 | runtime->status->state = SNDRV_PCM_STATE_PREPARED; | 1331 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); |
| 1324 | } | 1332 | } |
| 1325 | 1333 | ||
| 1326 | static struct action_ops snd_pcm_action_prepare = { | 1334 | static struct action_ops snd_pcm_action_prepare = { |
| @@ -1510,6 +1518,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, | |||
| 1510 | down_read(&snd_pcm_link_rwsem); | 1518 | down_read(&snd_pcm_link_rwsem); |
| 1511 | snd_pcm_stream_lock_irq(substream); | 1519 | snd_pcm_stream_lock_irq(substream); |
| 1512 | remove_wait_queue(&to_check->sleep, &wait); | 1520 | remove_wait_queue(&to_check->sleep, &wait); |
| 1521 | if (card->shutdown) { | ||
| 1522 | result = -ENODEV; | ||
| 1523 | break; | ||
| 1524 | } | ||
| 1513 | if (tout == 0) { | 1525 | if (tout == 0) { |
| 1514 | if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) | 1526 | if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) |
| 1515 | result = -ESTRPIPE; | 1527 | result = -ESTRPIPE; |
| @@ -1634,6 +1646,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) | |||
| 1634 | write_unlock_irq(&snd_pcm_link_rwlock); | 1646 | write_unlock_irq(&snd_pcm_link_rwlock); |
| 1635 | up_write(&snd_pcm_link_rwsem); | 1647 | up_write(&snd_pcm_link_rwsem); |
| 1636 | _nolock: | 1648 | _nolock: |
| 1649 | snd_card_unref(substream1->pcm->card); | ||
| 1637 | fput_light(file, fput_needed); | 1650 | fput_light(file, fput_needed); |
| 1638 | if (res < 0) | 1651 | if (res < 0) |
| 1639 | kfree(group); | 1652 | kfree(group); |
| @@ -2108,7 +2121,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) | |||
| 2108 | return err; | 2121 | return err; |
| 2109 | pcm = snd_lookup_minor_data(iminor(inode), | 2122 | pcm = snd_lookup_minor_data(iminor(inode), |
| 2110 | SNDRV_DEVICE_TYPE_PCM_PLAYBACK); | 2123 | SNDRV_DEVICE_TYPE_PCM_PLAYBACK); |
| 2111 | return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); | 2124 | err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); |
| 2125 | snd_card_unref(pcm->card); | ||
| 2126 | return err; | ||
| 2112 | } | 2127 | } |
| 2113 | 2128 | ||
| 2114 | static int snd_pcm_capture_open(struct inode *inode, struct file *file) | 2129 | static int snd_pcm_capture_open(struct inode *inode, struct file *file) |
| @@ -2119,7 +2134,9 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file) | |||
| 2119 | return err; | 2134 | return err; |
| 2120 | pcm = snd_lookup_minor_data(iminor(inode), | 2135 | pcm = snd_lookup_minor_data(iminor(inode), |
| 2121 | SNDRV_DEVICE_TYPE_PCM_CAPTURE); | 2136 | SNDRV_DEVICE_TYPE_PCM_CAPTURE); |
| 2122 | return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); | 2137 | err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); |
| 2138 | snd_card_unref(pcm->card); | ||
| 2139 | return err; | ||
| 2123 | } | 2140 | } |
| 2124 | 2141 | ||
| 2125 | static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) | 2142 | static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) |
| @@ -2156,6 +2173,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) | |||
| 2156 | mutex_unlock(&pcm->open_mutex); | 2173 | mutex_unlock(&pcm->open_mutex); |
| 2157 | schedule(); | 2174 | schedule(); |
| 2158 | mutex_lock(&pcm->open_mutex); | 2175 | mutex_lock(&pcm->open_mutex); |
| 2176 | if (pcm->card->shutdown) { | ||
| 2177 | err = -ENODEV; | ||
| 2178 | break; | ||
| 2179 | } | ||
| 2159 | if (signal_pending(current)) { | 2180 | if (signal_pending(current)) { |
| 2160 | err = -ERESTARTSYS; | 2181 | err = -ERESTARTSYS; |
| 2161 | break; | 2182 | break; |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ebf6e49ad3d4..1bb95aeea084 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
| @@ -379,8 +379,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
| 379 | if (rmidi == NULL) | 379 | if (rmidi == NULL) |
| 380 | return -ENODEV; | 380 | return -ENODEV; |
| 381 | 381 | ||
| 382 | if (!try_module_get(rmidi->card->module)) | 382 | if (!try_module_get(rmidi->card->module)) { |
| 383 | snd_card_unref(rmidi->card); | ||
| 383 | return -ENXIO; | 384 | return -ENXIO; |
| 385 | } | ||
| 384 | 386 | ||
| 385 | mutex_lock(&rmidi->open_mutex); | 387 | mutex_lock(&rmidi->open_mutex); |
| 386 | card = rmidi->card; | 388 | card = rmidi->card; |
| @@ -422,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
| 422 | mutex_unlock(&rmidi->open_mutex); | 424 | mutex_unlock(&rmidi->open_mutex); |
| 423 | schedule(); | 425 | schedule(); |
| 424 | mutex_lock(&rmidi->open_mutex); | 426 | mutex_lock(&rmidi->open_mutex); |
| 427 | if (rmidi->card->shutdown) { | ||
| 428 | err = -ENODEV; | ||
| 429 | break; | ||
| 430 | } | ||
| 425 | if (signal_pending(current)) { | 431 | if (signal_pending(current)) { |
| 426 | err = -ERESTARTSYS; | 432 | err = -ERESTARTSYS; |
| 427 | break; | 433 | break; |
| @@ -440,6 +446,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
| 440 | #endif | 446 | #endif |
| 441 | file->private_data = rawmidi_file; | 447 | file->private_data = rawmidi_file; |
| 442 | mutex_unlock(&rmidi->open_mutex); | 448 | mutex_unlock(&rmidi->open_mutex); |
| 449 | snd_card_unref(rmidi->card); | ||
| 443 | return 0; | 450 | return 0; |
| 444 | 451 | ||
| 445 | __error: | 452 | __error: |
| @@ -447,6 +454,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
| 447 | __error_card: | 454 | __error_card: |
| 448 | mutex_unlock(&rmidi->open_mutex); | 455 | mutex_unlock(&rmidi->open_mutex); |
| 449 | module_put(rmidi->card->module); | 456 | module_put(rmidi->card->module); |
| 457 | snd_card_unref(rmidi->card); | ||
| 450 | return err; | 458 | return err; |
| 451 | } | 459 | } |
| 452 | 460 | ||
| @@ -991,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun | |||
| 991 | spin_unlock_irq(&runtime->lock); | 999 | spin_unlock_irq(&runtime->lock); |
| 992 | schedule(); | 1000 | schedule(); |
| 993 | remove_wait_queue(&runtime->sleep, &wait); | 1001 | remove_wait_queue(&runtime->sleep, &wait); |
| 1002 | if (rfile->rmidi->card->shutdown) | ||
| 1003 | return -ENODEV; | ||
| 994 | if (signal_pending(current)) | 1004 | if (signal_pending(current)) |
| 995 | return result > 0 ? result : -ERESTARTSYS; | 1005 | return result > 0 ? result : -ERESTARTSYS; |
| 996 | if (!runtime->avail) | 1006 | if (!runtime->avail) |
| @@ -1234,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, | |||
| 1234 | spin_unlock_irq(&runtime->lock); | 1244 | spin_unlock_irq(&runtime->lock); |
| 1235 | timeout = schedule_timeout(30 * HZ); | 1245 | timeout = schedule_timeout(30 * HZ); |
| 1236 | remove_wait_queue(&runtime->sleep, &wait); | 1246 | remove_wait_queue(&runtime->sleep, &wait); |
| 1247 | if (rfile->rmidi->card->shutdown) | ||
| 1248 | return -ENODEV; | ||
| 1237 | if (signal_pending(current)) | 1249 | if (signal_pending(current)) |
| 1238 | return result > 0 ? result : -ERESTARTSYS; | 1250 | return result > 0 ? result : -ERESTARTSYS; |
| 1239 | if (!runtime->avail && !timeout) | 1251 | if (!runtime->avail && !timeout) |
| @@ -1609,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device) | |||
| 1609 | static int snd_rawmidi_dev_disconnect(struct snd_device *device) | 1621 | static int snd_rawmidi_dev_disconnect(struct snd_device *device) |
| 1610 | { | 1622 | { |
| 1611 | struct snd_rawmidi *rmidi = device->device_data; | 1623 | struct snd_rawmidi *rmidi = device->device_data; |
| 1624 | int dir; | ||
| 1612 | 1625 | ||
| 1613 | mutex_lock(®ister_mutex); | 1626 | mutex_lock(®ister_mutex); |
| 1627 | mutex_lock(&rmidi->open_mutex); | ||
| 1628 | wake_up(&rmidi->open_wait); | ||
| 1614 | list_del_init(&rmidi->list); | 1629 | list_del_init(&rmidi->list); |
| 1630 | for (dir = 0; dir < 2; dir++) { | ||
| 1631 | struct snd_rawmidi_substream *s; | ||
| 1632 | list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { | ||
| 1633 | if (s->runtime) | ||
| 1634 | wake_up(&s->runtime->sleep); | ||
| 1635 | } | ||
| 1636 | } | ||
| 1637 | |||
| 1615 | #ifdef CONFIG_SND_OSSEMUL | 1638 | #ifdef CONFIG_SND_OSSEMUL |
| 1616 | if (rmidi->ossreg) { | 1639 | if (rmidi->ossreg) { |
| 1617 | if ((int)rmidi->device == midi_map[rmidi->card->number]) { | 1640 | if ((int)rmidi->device == midi_map[rmidi->card->number]) { |
| @@ -1626,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) | |||
| 1626 | } | 1649 | } |
| 1627 | #endif /* CONFIG_SND_OSSEMUL */ | 1650 | #endif /* CONFIG_SND_OSSEMUL */ |
| 1628 | snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); | 1651 | snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); |
| 1652 | mutex_unlock(&rmidi->open_mutex); | ||
| 1629 | mutex_unlock(®ister_mutex); | 1653 | mutex_unlock(®ister_mutex); |
| 1630 | return 0; | 1654 | return 0; |
| 1631 | } | 1655 | } |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 643976000ce8..89780c323f19 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
| @@ -98,6 +98,10 @@ static void snd_request_other(int minor) | |||
| 98 | * | 98 | * |
| 99 | * Checks that a minor device with the specified type is registered, and returns | 99 | * Checks that a minor device with the specified type is registered, and returns |
| 100 | * its user data pointer. | 100 | * its user data pointer. |
| 101 | * | ||
| 102 | * This function increments the reference counter of the card instance | ||
| 103 | * if an associated instance with the given minor number and type is found. | ||
| 104 | * The caller must call snd_card_unref() appropriately later. | ||
| 101 | */ | 105 | */ |
| 102 | void *snd_lookup_minor_data(unsigned int minor, int type) | 106 | void *snd_lookup_minor_data(unsigned int minor, int type) |
| 103 | { | 107 | { |
| @@ -108,9 +112,11 @@ void *snd_lookup_minor_data(unsigned int minor, int type) | |||
| 108 | return NULL; | 112 | return NULL; |
| 109 | mutex_lock(&sound_mutex); | 113 | mutex_lock(&sound_mutex); |
| 110 | mreg = snd_minors[minor]; | 114 | mreg = snd_minors[minor]; |
| 111 | if (mreg && mreg->type == type) | 115 | if (mreg && mreg->type == type) { |
| 112 | private_data = mreg->private_data; | 116 | private_data = mreg->private_data; |
| 113 | else | 117 | if (mreg->card_ptr) |
| 118 | atomic_inc(&mreg->card_ptr->refcount); | ||
| 119 | } else | ||
| 114 | private_data = NULL; | 120 | private_data = NULL; |
| 115 | mutex_unlock(&sound_mutex); | 121 | mutex_unlock(&sound_mutex); |
| 116 | return private_data; | 122 | return private_data; |
| @@ -275,6 +281,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, | |||
| 275 | preg->device = dev; | 281 | preg->device = dev; |
| 276 | preg->f_ops = f_ops; | 282 | preg->f_ops = f_ops; |
| 277 | preg->private_data = private_data; | 283 | preg->private_data = private_data; |
| 284 | preg->card_ptr = card; | ||
| 278 | mutex_lock(&sound_mutex); | 285 | mutex_lock(&sound_mutex); |
| 279 | #ifdef CONFIG_SND_DYNAMIC_MINORS | 286 | #ifdef CONFIG_SND_DYNAMIC_MINORS |
| 280 | minor = snd_find_free_minor(type); | 287 | minor = snd_find_free_minor(type); |
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index e9528333e36d..e1d79ee35906 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c | |||
| @@ -40,6 +40,9 @@ | |||
| 40 | static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS]; | 40 | static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS]; |
| 41 | static DEFINE_MUTEX(sound_oss_mutex); | 41 | static DEFINE_MUTEX(sound_oss_mutex); |
| 42 | 42 | ||
| 43 | /* NOTE: This function increments the refcount of the associated card like | ||
| 44 | * snd_lookup_minor_data(); the caller must call snd_card_unref() appropriately | ||
| 45 | */ | ||
| 43 | void *snd_lookup_oss_minor_data(unsigned int minor, int type) | 46 | void *snd_lookup_oss_minor_data(unsigned int minor, int type) |
| 44 | { | 47 | { |
| 45 | struct snd_minor *mreg; | 48 | struct snd_minor *mreg; |
| @@ -49,9 +52,11 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) | |||
| 49 | return NULL; | 52 | return NULL; |
| 50 | mutex_lock(&sound_oss_mutex); | 53 | mutex_lock(&sound_oss_mutex); |
| 51 | mreg = snd_oss_minors[minor]; | 54 | mreg = snd_oss_minors[minor]; |
| 52 | if (mreg && mreg->type == type) | 55 | if (mreg && mreg->type == type) { |
| 53 | private_data = mreg->private_data; | 56 | private_data = mreg->private_data; |
| 54 | else | 57 | if (mreg->card_ptr) |
| 58 | atomic_inc(&mreg->card_ptr->refcount); | ||
| 59 | } else | ||
| 55 | private_data = NULL; | 60 | private_data = NULL; |
| 56 | mutex_unlock(&sound_oss_mutex); | 61 | mutex_unlock(&sound_oss_mutex); |
| 57 | return private_data; | 62 | return private_data; |
| @@ -123,6 +128,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, | |||
| 123 | preg->device = dev; | 128 | preg->device = dev; |
| 124 | preg->f_ops = f_ops; | 129 | preg->f_ops = f_ops; |
| 125 | preg->private_data = private_data; | 130 | preg->private_data = private_data; |
| 131 | preg->card_ptr = card; | ||
| 126 | mutex_lock(&sound_oss_mutex); | 132 | mutex_lock(&sound_oss_mutex); |
| 127 | snd_oss_minors[minor] = preg; | 133 | snd_oss_minors[minor] = preg; |
| 128 | minor_unit = SNDRV_MINOR_OSS_DEVICE(minor); | 134 | minor_unit = SNDRV_MINOR_OSS_DEVICE(minor); |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 770013ff556f..9ba8af056170 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
| @@ -1763,6 +1763,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | |||
| 1763 | "HP", STAC_HP_ZEPHYR), | 1763 | "HP", STAC_HP_ZEPHYR), |
| 1764 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660, | 1764 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660, |
| 1765 | "HP Mini", STAC_92HD83XXX_HP_LED), | 1765 | "HP Mini", STAC_92HD83XXX_HP_LED), |
| 1766 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E, | ||
| 1767 | "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED), | ||
| 1766 | {} /* terminator */ | 1768 | {} /* terminator */ |
| 1767 | }; | 1769 | }; |
| 1768 | 1770 | ||
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 3050a5279253..245d874891ba 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
| @@ -2859,7 +2859,12 @@ static int snd_vt1724_resume(struct device *dev) | |||
| 2859 | ice->set_spdif_clock(ice, 0); | 2859 | ice->set_spdif_clock(ice, 0); |
| 2860 | } else { | 2860 | } else { |
| 2861 | /* internal on-card clock */ | 2861 | /* internal on-card clock */ |
| 2862 | snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); | 2862 | int rate; |
| 2863 | if (ice->cur_rate) | ||
| 2864 | rate = ice->cur_rate; | ||
| 2865 | else | ||
| 2866 | rate = ice->pro_rate_default; | ||
| 2867 | snd_vt1724_set_pro_rate(ice, rate, 1); | ||
| 2863 | } | 2868 | } |
| 2864 | 2869 | ||
| 2865 | update_spdif_bits(ice, ice->pm_saved_spdif_ctrl); | 2870 | update_spdif_bits(ice, ice->pm_saved_spdif_ctrl); |
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 68f2cd1a9206..5a6aeaf552a8 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c | |||
| @@ -464,9 +464,9 @@ static __devinit int asoc_dmic_probe(struct platform_device *pdev) | |||
| 464 | 464 | ||
| 465 | mutex_init(&dmic->mutex); | 465 | mutex_init(&dmic->mutex); |
| 466 | 466 | ||
| 467 | dmic->fclk = clk_get(dmic->dev, "dmic_fck"); | 467 | dmic->fclk = clk_get(dmic->dev, "fck"); |
| 468 | if (IS_ERR(dmic->fclk)) { | 468 | if (IS_ERR(dmic->fclk)) { |
| 469 | dev_err(dmic->dev, "cant get dmic_fck\n"); | 469 | dev_err(dmic->dev, "cant get fck\n"); |
| 470 | return -ENODEV; | 470 | return -ENODEV; |
| 471 | } | 471 | } |
| 472 | 472 | ||
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 677b567935f8..1ff6bb9ade5c 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c | |||
| @@ -21,15 +21,14 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
| 23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
| 24 | #include <linux/gpio.h> | ||
| 24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
| 25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
| 26 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
| 27 | 28 | ||
| 28 | #include <asm/mach-types.h> | 29 | #include <asm/mach-types.h> |
| 29 | #include <mach/hardware.h> | ||
| 30 | #include <mach/gpio.h> | ||
| 31 | #include <mach/board-zoom.h> | ||
| 32 | #include <linux/platform_data/asoc-ti-mcbsp.h> | 30 | #include <linux/platform_data/asoc-ti-mcbsp.h> |
| 31 | #include <linux/platform_data/gpio-omap.h> | ||
| 33 | 32 | ||
| 34 | /* Register descriptions for twl4030 codec part */ | 33 | /* Register descriptions for twl4030 codec part */ |
| 35 | #include <linux/mfd/twl4030-audio.h> | 34 | #include <linux/mfd/twl4030-audio.h> |
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 55e19e1b80ec..37428f74dbb6 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,19 @@ 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 | } | ||
| 557 | 570 | ||
| 558 | ret = set_format(subs, subs->cur_audiofmt); | 571 | ret = set_format(subs, subs->cur_audiofmt); |
| 559 | if (ret < 0) | 572 | if (ret < 0) |
| 560 | return ret; | 573 | goto unlock; |
| 561 | 574 | ||
| 562 | iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); | 575 | iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); |
| 563 | alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; | 576 | alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; |
| @@ -567,12 +580,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 567 | subs->cur_audiofmt, | 580 | subs->cur_audiofmt, |
| 568 | subs->cur_rate); | 581 | subs->cur_rate); |
| 569 | if (ret < 0) | 582 | if (ret < 0) |
| 570 | return ret; | 583 | goto unlock; |
| 571 | 584 | ||
| 572 | if (subs->need_setup_ep) { | 585 | if (subs->need_setup_ep) { |
| 573 | ret = configure_endpoint(subs); | 586 | ret = configure_endpoint(subs); |
| 574 | if (ret < 0) | 587 | if (ret < 0) |
| 575 | return ret; | 588 | goto unlock; |
| 576 | subs->need_setup_ep = false; | 589 | subs->need_setup_ep = false; |
| 577 | } | 590 | } |
| 578 | 591 | ||
| @@ -592,9 +605,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 592 | /* for playback, submit the URBs now; otherwise, the first hwptr_done | 605 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
| 593 | * updates for all URBs would happen at the same time when starting */ | 606 | * updates for all URBs would happen at the same time when starting */ |
| 594 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) | 607 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) |
| 595 | return start_endpoints(subs, 1); | 608 | ret = start_endpoints(subs, 1); |
| 596 | 609 | ||
| 597 | return 0; | 610 | unlock: |
| 611 | up_read(&subs->stream->chip->shutdown_rwsem); | ||
| 612 | return ret; | ||
| 598 | } | 613 | } |
| 599 | 614 | ||
| 600 | static struct snd_pcm_hardware snd_usb_hardware = | 615 | static struct snd_pcm_hardware snd_usb_hardware = |
| @@ -647,7 +662,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, | |||
| 647 | return 0; | 662 | return 0; |
| 648 | } | 663 | } |
| 649 | /* check whether the period time is >= the data packet interval */ | 664 | /* check whether the period time is >= the data packet interval */ |
| 650 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { | 665 | if (subs->speed != USB_SPEED_FULL) { |
| 651 | ptime = 125 * (1 << fp->datainterval); | 666 | ptime = 125 * (1 << fp->datainterval); |
| 652 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | 667 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { |
| 653 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | 668 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); |
| @@ -925,7 +940,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
| 925 | return err; | 940 | return err; |
| 926 | 941 | ||
| 927 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 942 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
| 928 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 943 | if (subs->speed == USB_SPEED_FULL) |
| 929 | /* full speed devices have fixed data packet interval */ | 944 | /* full speed devices have fixed data packet interval */ |
| 930 | ptmin = 1000; | 945 | ptmin = 1000; |
| 931 | if (ptmin == 1000) | 946 | 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; |
