Loading include/sound/core.h +46 −4 Original line number Diff line number Diff line Loading @@ -128,7 +128,9 @@ struct snd_card { #ifdef CONFIG_PM unsigned int power_state; /* power state */ atomic_t power_ref; wait_queue_head_t power_sleep; wait_queue_head_t power_ref_sleep; #endif #if IS_ENABLED(CONFIG_SND_MIXER_OSS) Loading @@ -142,21 +144,61 @@ struct snd_card { #ifdef CONFIG_PM static inline unsigned int snd_power_get_state(struct snd_card *card) { return card->power_state; return READ_ONCE(card->power_state); } static inline void snd_power_change_state(struct snd_card *card, unsigned int state) { card->power_state = state; WRITE_ONCE(card->power_state, state); wake_up(&card->power_sleep); } /** * snd_power_ref - Take the reference count for power control * @card: sound card object * * The power_ref reference of the card is used for managing to block * the snd_power_sync_ref() operation. This function increments the reference. * The counterpart snd_power_unref() has to be called appropriately later. */ static inline void snd_power_ref(struct snd_card *card) { atomic_inc(&card->power_ref); } /** * snd_power_unref - Release the reference count for power control * @card: sound card object */ static inline void snd_power_unref(struct snd_card *card) { if (atomic_dec_and_test(&card->power_ref)) wake_up(&card->power_ref_sleep); } /** * snd_power_sync_ref - wait until the card power_ref is freed * @card: sound card object * * This function is used to synchronize with the pending power_ref being * released. */ static inline void snd_power_sync_ref(struct snd_card *card) { wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref)); } /* init.c */ int snd_power_wait(struct snd_card *card, unsigned int power_state); int snd_power_wait(struct snd_card *card); int snd_power_ref_and_wait(struct snd_card *card); #else /* ! CONFIG_PM */ static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; } static inline int snd_power_wait(struct snd_card *card) { return 0; } static inline void snd_power_ref(struct snd_card *card) {} static inline void snd_power_unref(struct snd_card *card) {} static inline int snd_power_ref_and_wait(struct snd_card *card) { return 0; } static inline void snd_power_sync_ref(struct snd_card *card) {} #define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; }) #define snd_power_change_state(card, state) do { (void)(card); } while (0) Loading sound/core/control.c +18 −20 Original line number Diff line number Diff line Loading @@ -995,7 +995,10 @@ static int __snd_ctl_elem_info(struct snd_card *card, #ifdef CONFIG_SND_DEBUG info->access = 0; #endif result = snd_power_ref_and_wait(card); if (!result) result = kctl->info(kctl, info); snd_power_unref(card); if (result >= 0) { snd_BUG_ON(info->access); index_offset = snd_ctl_get_ioff(kctl, &info->id); Loading Loading @@ -1042,9 +1045,6 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); if (result < 0) return result; result = snd_ctl_elem_info(ctl, &info); if (result < 0) return result; Loading Loading @@ -1088,7 +1088,10 @@ static int snd_ctl_elem_read(struct snd_card *card, if (!snd_ctl_skip_validation(&info)) fill_remaining_elem_value(control, &info, pattern); ret = snd_power_ref_and_wait(card); if (!ret) ret = kctl->get(kctl, control); snd_power_unref(card); if (ret < 0) return ret; if (!snd_ctl_skip_validation(&info) && Loading @@ -1113,10 +1116,6 @@ static int snd_ctl_elem_read_user(struct snd_card *card, if (IS_ERR(control)) return PTR_ERR(control); result = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (result < 0) goto error; down_read(&card->controls_rwsem); result = snd_ctl_elem_read(card, control); up_read(&card->controls_rwsem); Loading Loading @@ -1154,7 +1153,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, } snd_ctl_build_ioff(&control->id, kctl, index_offset); result = snd_power_ref_and_wait(card); if (!result) result = kctl->put(kctl, control); snd_power_unref(card); if (result < 0) { up_write(&card->controls_rwsem); return result; Loading Loading @@ -1183,10 +1185,6 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, return PTR_ERR(control); card = file->card; result = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (result < 0) goto error; result = snd_ctl_elem_write(card, file, control); if (result < 0) goto error; Loading Loading @@ -1669,7 +1667,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, }; struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; int i; int i, ret; /* Check support of the request for this element. */ for (i = 0; i < ARRAY_SIZE(pairs); ++i) { Loading @@ -1687,7 +1685,11 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, vd->owner != NULL && vd->owner != file) return -EPERM; return kctl->tlv.c(kctl, op_flag, size, buf); ret = snd_power_ref_and_wait(file->card); if (!ret) ret = kctl->tlv.c(kctl, op_flag, size, buf); snd_power_unref(file->card); return ret; } static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id, Loading Loading @@ -1815,11 +1817,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; case SNDRV_CTL_IOCTL_POWER_STATE: #ifdef CONFIG_PM return put_user(card->power_state, ip) ? -EFAULT : 0; #else return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0; #endif } down_read(&snd_ioctl_rwsem); list_for_each_entry(p, &snd_control_ioctls, list) { Loading sound/core/control_compat.c +4 −10 Original line number Diff line number Diff line Loading @@ -96,9 +96,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) goto error; err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; err = snd_ctl_elem_info(ctl, data); if (err < 0) goto error; Loading Loading @@ -187,7 +184,10 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, return -ENOMEM; } info->id = *id; err = snd_power_ref_and_wait(card); if (!err) err = kctl->info(kctl, info); snd_power_unref(card); up_read(&card->controls_rwsem); if (err >= 0) { err = info->type; Loading Loading @@ -298,9 +298,6 @@ static int ctl_elem_read_user(struct snd_card *card, if (err < 0) goto error; err = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; err = snd_ctl_elem_read(card, data); if (err < 0) goto error; Loading @@ -326,9 +323,6 @@ static int ctl_elem_write_user(struct snd_ctl_file *file, if (err < 0) goto error; err = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; err = snd_ctl_elem_write(card, file, data); if (err < 0) goto error; Loading sound/core/init.c +38 −8 Original line number Diff line number Diff line Loading @@ -220,6 +220,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid, mutex_init(&card->memory_mutex); #ifdef CONFIG_PM init_waitqueue_head(&card->power_sleep); init_waitqueue_head(&card->power_ref_sleep); atomic_set(&card->power_ref, 0); #endif init_waitqueue_head(&card->remove_sleep); card->sync_irq = -1; Loading Loading @@ -442,6 +444,7 @@ int snd_card_disconnect(struct snd_card *card) #ifdef CONFIG_PM wake_up(&card->power_sleep); snd_power_sync_ref(card); #endif return 0; } Loading Loading @@ -1002,21 +1005,28 @@ EXPORT_SYMBOL(snd_card_file_remove); #ifdef CONFIG_PM /** * snd_power_wait - wait until the power-state is changed. * snd_power_ref_and_wait - wait until the card gets powered up * @card: soundcard structure * @power_state: expected power state * * Waits until the power-state is changed. * Take the power_ref reference count of the given card, and * wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. * The refcount is down again while sleeping until power-up, hence this * function can be used for syncing the floating control ops accesses, * typically around calling control ops. * * The caller needs to pull down the refcount via snd_power_unref() later * no matter whether the error is returned from this function or not. * * Return: Zero if successful, or a negative error code. */ int snd_power_wait(struct snd_card *card, unsigned int power_state) int snd_power_ref_and_wait(struct snd_card *card) { wait_queue_entry_t wait; int result = 0; snd_power_ref(card); /* fastpath */ if (snd_power_get_state(card) == power_state) if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) return 0; init_waitqueue_entry(&wait, current); add_wait_queue(&card->power_sleep, &wait); Loading @@ -1025,13 +1035,33 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) result = -ENODEV; break; } if (snd_power_get_state(card) == power_state) if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) break; snd_power_unref(card); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(30 * HZ); snd_power_ref(card); } remove_wait_queue(&card->power_sleep, &wait); return result; } EXPORT_SYMBOL_GPL(snd_power_ref_and_wait); /** * snd_power_wait - wait until the card gets powered up (old form) * @card: soundcard structure * * Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. * * Return: Zero if successful, or a negative error code. */ int snd_power_wait(struct snd_card *card) { int ret; ret = snd_power_ref_and_wait(card); snd_power_unref(card); return ret; } EXPORT_SYMBOL(snd_power_wait); #endif /* CONFIG_PM */ sound/core/pcm_native.c +5 −1 Original line number Diff line number Diff line Loading @@ -2799,6 +2799,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file) if (snd_BUG_ON(!substream)) return -ENXIO; pcm = substream->pcm; /* block until the device gets woken up as it may touch the hardware */ snd_power_wait(pcm->card); mutex_lock(&pcm->open_mutex); snd_pcm_release_substream(substream); kfree(pcm_file); Loading Loading @@ -3193,7 +3197,7 @@ static int snd_pcm_common_ioctl(struct file *file, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0); res = snd_power_wait(substream->pcm->card); if (res < 0) return res; Loading Loading
include/sound/core.h +46 −4 Original line number Diff line number Diff line Loading @@ -128,7 +128,9 @@ struct snd_card { #ifdef CONFIG_PM unsigned int power_state; /* power state */ atomic_t power_ref; wait_queue_head_t power_sleep; wait_queue_head_t power_ref_sleep; #endif #if IS_ENABLED(CONFIG_SND_MIXER_OSS) Loading @@ -142,21 +144,61 @@ struct snd_card { #ifdef CONFIG_PM static inline unsigned int snd_power_get_state(struct snd_card *card) { return card->power_state; return READ_ONCE(card->power_state); } static inline void snd_power_change_state(struct snd_card *card, unsigned int state) { card->power_state = state; WRITE_ONCE(card->power_state, state); wake_up(&card->power_sleep); } /** * snd_power_ref - Take the reference count for power control * @card: sound card object * * The power_ref reference of the card is used for managing to block * the snd_power_sync_ref() operation. This function increments the reference. * The counterpart snd_power_unref() has to be called appropriately later. */ static inline void snd_power_ref(struct snd_card *card) { atomic_inc(&card->power_ref); } /** * snd_power_unref - Release the reference count for power control * @card: sound card object */ static inline void snd_power_unref(struct snd_card *card) { if (atomic_dec_and_test(&card->power_ref)) wake_up(&card->power_ref_sleep); } /** * snd_power_sync_ref - wait until the card power_ref is freed * @card: sound card object * * This function is used to synchronize with the pending power_ref being * released. */ static inline void snd_power_sync_ref(struct snd_card *card) { wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref)); } /* init.c */ int snd_power_wait(struct snd_card *card, unsigned int power_state); int snd_power_wait(struct snd_card *card); int snd_power_ref_and_wait(struct snd_card *card); #else /* ! CONFIG_PM */ static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; } static inline int snd_power_wait(struct snd_card *card) { return 0; } static inline void snd_power_ref(struct snd_card *card) {} static inline void snd_power_unref(struct snd_card *card) {} static inline int snd_power_ref_and_wait(struct snd_card *card) { return 0; } static inline void snd_power_sync_ref(struct snd_card *card) {} #define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; }) #define snd_power_change_state(card, state) do { (void)(card); } while (0) Loading
sound/core/control.c +18 −20 Original line number Diff line number Diff line Loading @@ -995,7 +995,10 @@ static int __snd_ctl_elem_info(struct snd_card *card, #ifdef CONFIG_SND_DEBUG info->access = 0; #endif result = snd_power_ref_and_wait(card); if (!result) result = kctl->info(kctl, info); snd_power_unref(card); if (result >= 0) { snd_BUG_ON(info->access); index_offset = snd_ctl_get_ioff(kctl, &info->id); Loading Loading @@ -1042,9 +1045,6 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); if (result < 0) return result; result = snd_ctl_elem_info(ctl, &info); if (result < 0) return result; Loading Loading @@ -1088,7 +1088,10 @@ static int snd_ctl_elem_read(struct snd_card *card, if (!snd_ctl_skip_validation(&info)) fill_remaining_elem_value(control, &info, pattern); ret = snd_power_ref_and_wait(card); if (!ret) ret = kctl->get(kctl, control); snd_power_unref(card); if (ret < 0) return ret; if (!snd_ctl_skip_validation(&info) && Loading @@ -1113,10 +1116,6 @@ static int snd_ctl_elem_read_user(struct snd_card *card, if (IS_ERR(control)) return PTR_ERR(control); result = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (result < 0) goto error; down_read(&card->controls_rwsem); result = snd_ctl_elem_read(card, control); up_read(&card->controls_rwsem); Loading Loading @@ -1154,7 +1153,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, } snd_ctl_build_ioff(&control->id, kctl, index_offset); result = snd_power_ref_and_wait(card); if (!result) result = kctl->put(kctl, control); snd_power_unref(card); if (result < 0) { up_write(&card->controls_rwsem); return result; Loading Loading @@ -1183,10 +1185,6 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, return PTR_ERR(control); card = file->card; result = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (result < 0) goto error; result = snd_ctl_elem_write(card, file, control); if (result < 0) goto error; Loading Loading @@ -1669,7 +1667,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, }; struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; int i; int i, ret; /* Check support of the request for this element. */ for (i = 0; i < ARRAY_SIZE(pairs); ++i) { Loading @@ -1687,7 +1685,11 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, vd->owner != NULL && vd->owner != file) return -EPERM; return kctl->tlv.c(kctl, op_flag, size, buf); ret = snd_power_ref_and_wait(file->card); if (!ret) ret = kctl->tlv.c(kctl, op_flag, size, buf); snd_power_unref(file->card); return ret; } static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id, Loading Loading @@ -1815,11 +1817,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; case SNDRV_CTL_IOCTL_POWER_STATE: #ifdef CONFIG_PM return put_user(card->power_state, ip) ? -EFAULT : 0; #else return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0; #endif } down_read(&snd_ioctl_rwsem); list_for_each_entry(p, &snd_control_ioctls, list) { Loading
sound/core/control_compat.c +4 −10 Original line number Diff line number Diff line Loading @@ -96,9 +96,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) goto error; err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; err = snd_ctl_elem_info(ctl, data); if (err < 0) goto error; Loading Loading @@ -187,7 +184,10 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, return -ENOMEM; } info->id = *id; err = snd_power_ref_and_wait(card); if (!err) err = kctl->info(kctl, info); snd_power_unref(card); up_read(&card->controls_rwsem); if (err >= 0) { err = info->type; Loading Loading @@ -298,9 +298,6 @@ static int ctl_elem_read_user(struct snd_card *card, if (err < 0) goto error; err = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; err = snd_ctl_elem_read(card, data); if (err < 0) goto error; Loading @@ -326,9 +323,6 @@ static int ctl_elem_write_user(struct snd_ctl_file *file, if (err < 0) goto error; err = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; err = snd_ctl_elem_write(card, file, data); if (err < 0) goto error; Loading
sound/core/init.c +38 −8 Original line number Diff line number Diff line Loading @@ -220,6 +220,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid, mutex_init(&card->memory_mutex); #ifdef CONFIG_PM init_waitqueue_head(&card->power_sleep); init_waitqueue_head(&card->power_ref_sleep); atomic_set(&card->power_ref, 0); #endif init_waitqueue_head(&card->remove_sleep); card->sync_irq = -1; Loading Loading @@ -442,6 +444,7 @@ int snd_card_disconnect(struct snd_card *card) #ifdef CONFIG_PM wake_up(&card->power_sleep); snd_power_sync_ref(card); #endif return 0; } Loading Loading @@ -1002,21 +1005,28 @@ EXPORT_SYMBOL(snd_card_file_remove); #ifdef CONFIG_PM /** * snd_power_wait - wait until the power-state is changed. * snd_power_ref_and_wait - wait until the card gets powered up * @card: soundcard structure * @power_state: expected power state * * Waits until the power-state is changed. * Take the power_ref reference count of the given card, and * wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. * The refcount is down again while sleeping until power-up, hence this * function can be used for syncing the floating control ops accesses, * typically around calling control ops. * * The caller needs to pull down the refcount via snd_power_unref() later * no matter whether the error is returned from this function or not. * * Return: Zero if successful, or a negative error code. */ int snd_power_wait(struct snd_card *card, unsigned int power_state) int snd_power_ref_and_wait(struct snd_card *card) { wait_queue_entry_t wait; int result = 0; snd_power_ref(card); /* fastpath */ if (snd_power_get_state(card) == power_state) if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) return 0; init_waitqueue_entry(&wait, current); add_wait_queue(&card->power_sleep, &wait); Loading @@ -1025,13 +1035,33 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) result = -ENODEV; break; } if (snd_power_get_state(card) == power_state) if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) break; snd_power_unref(card); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(30 * HZ); snd_power_ref(card); } remove_wait_queue(&card->power_sleep, &wait); return result; } EXPORT_SYMBOL_GPL(snd_power_ref_and_wait); /** * snd_power_wait - wait until the card gets powered up (old form) * @card: soundcard structure * * Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. * * Return: Zero if successful, or a negative error code. */ int snd_power_wait(struct snd_card *card) { int ret; ret = snd_power_ref_and_wait(card); snd_power_unref(card); return ret; } EXPORT_SYMBOL(snd_power_wait); #endif /* CONFIG_PM */
sound/core/pcm_native.c +5 −1 Original line number Diff line number Diff line Loading @@ -2799,6 +2799,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file) if (snd_BUG_ON(!substream)) return -ENXIO; pcm = substream->pcm; /* block until the device gets woken up as it may touch the hardware */ snd_power_wait(pcm->card); mutex_lock(&pcm->open_mutex); snd_pcm_release_substream(substream); kfree(pcm_file); Loading Loading @@ -3193,7 +3197,7 @@ static int snd_pcm_common_ioctl(struct file *file, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0); res = snd_power_wait(substream->pcm->card); if (res < 0) return res; Loading