diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-04 11:46:02 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-04 11:46:02 -0700 |
| commit | abebcdfb64f1b39eeeb14282d9cd4aad1ed86f8d (patch) | |
| tree | 2c5ac5569cf4d101dd12732ae2ea5cd368cd0a13 /sound/usb/card.c | |
| parent | 670c039deeffb5c0a3a900de53b95dba781aaf89 (diff) | |
| parent | d5f362a7b977bdfaf8a955f3d604a29267bd5464 (diff) | |
Merge tag 'sound-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"There are little changes in core part, but lots of development are
found in drivers, especially ASoC. The diffstat shows regmap-related
changes for a slight API additions / changes, and that's all.
Looking at the code size statistics, the most significant addition is
for Intel Skylake. (Note that SKL support is still underway, the
codec driver is missing.) Also STI controller driver is a major
addition as well as a few new codec drivers.
In HD-audio side, there are fewer changes than the past. The
noticeable change is the support of ELD notification from i915
graphics driver. Thus this pull request carries a few changes in
drm/i915.
Other than that, USB-audio got a rewrite of runtime PM code. It was
initiated by lockdep warning, but resulted in a good cleanup in the
end.
Below are the highlights:
Common:
- Factoring out of AC'97 reset code from ASoC into the core helper
- A few regmap API extensions (in case it's not pulled yet)
ASoC:
- New drivers for Cirrus CS4349, GTM601, InvenSense ICS43432, Realtek
RT298 and ST STI controllers
- Machine drivers for Rockchip systems with MAX98090 and RT5645 and
RT5650
- Initial driver support for Intel Skylake devices
- Lots of rsnd cleanup and enhancements
- A few DAPM fixes and cleanups
- A large number of cleanups in various drivers (conversion and
standardized to regmap, component) mostly by Lars-Peter and Axel
HD-audio:
- Extended HD-audio core for Intel Skylake controller support
- Quirks for Dell headsets, Alienware 15
- Clean up of pin-based quirk tables for Realtek codecs
- ELD notifier implenetation for Intel HDMI/DP
USB-audio:
- Refactor runtime PM code to make lockdep happier"
* tag 'sound-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (411 commits)
drm/i915: Add locks around audio component bind/unbind
drm/i915: Drop port_mst_index parameter from pin/eld callback
ALSA: hda - Fix missing inline for dummy snd_hdac_set_codec_wakeup()
ALSA: hda - Wake the codec up on pin/ELD notify events
ALSA: hda - allow codecs to access the i915 pin/ELD callback
drm/i915: Call audio pin/ELD notify function
drm/i915: Add audio pin sense / ELD callback
ASoC: zx296702-i2s: Fix resource leak when unload module
ASoC: sti_uniperif: Ensure component is unregistered when unload module
ASoC: au1x: psc-i2s: Convert to use devm_ioremap_resource
ASoC: sh: dma-sh7760: Convert to devm_snd_soc_register_platform
ASoC: spear_pcm: Use devm_snd_dmaengine_pcm_register to fix resource leak
ALSA: fireworks/bebob/dice/oxfw: fix substreams counting at vmalloc failure
ASoC: Clean up docbook warnings
ASoC: txx9: Convert to devm_snd_soc_register_platform
ASoC: pxa: Convert to devm_snd_soc_register_platform
ASoC: nuc900: Convert to devm_snd_soc_register_platform
ASoC: blackfin: Convert to devm_snd_soc_register_platform
ASoC: au1x: Convert to devm_snd_soc_register_platform
ASoC: qcom: Constify asoc_qcom_lpass_cpu_dai_ops
...
Diffstat (limited to 'sound/usb/card.c')
| -rw-r--r-- | sound/usb/card.c | 108 |
1 files changed, 61 insertions, 47 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 0450593980fd..18f56646ce86 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -365,13 +365,15 @@ static int snd_usb_audio_create(struct usb_interface *intf, } mutex_init(&chip->mutex); - init_rwsem(&chip->shutdown_rwsem); + init_waitqueue_head(&chip->shutdown_wait); chip->index = idx; chip->dev = dev; chip->card = card; chip->setup = device_setup[idx]; chip->autoclock = autoclock; - chip->probing = 1; + atomic_set(&chip->active, 1); /* avoid autopm during probing */ + atomic_set(&chip->usage_count, 0); + atomic_set(&chip->shutdown, 0); chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); @@ -495,13 +497,13 @@ static int usb_audio_probe(struct usb_interface *intf, mutex_lock(®ister_mutex); for (i = 0; i < SNDRV_CARDS; i++) { if (usb_chip[i] && usb_chip[i]->dev == dev) { - if (usb_chip[i]->shutdown) { + if (atomic_read(&usb_chip[i]->shutdown)) { dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n"); err = -EIO; goto __error; } chip = usb_chip[i]; - chip->probing = 1; + atomic_inc(&chip->active); /* avoid autopm */ break; } } @@ -561,8 +563,8 @@ static int usb_audio_probe(struct usb_interface *intf, usb_chip[chip->index] = chip; chip->num_interfaces++; - chip->probing = 0; usb_set_intfdata(intf, chip); + atomic_dec(&chip->active); mutex_unlock(®ister_mutex); return 0; @@ -570,7 +572,7 @@ static int usb_audio_probe(struct usb_interface *intf, if (chip) { if (!chip->num_interfaces) snd_card_free(chip->card); - chip->probing = 0; + atomic_dec(&chip->active); } mutex_unlock(®ister_mutex); return err; @@ -585,23 +587,23 @@ static void usb_audio_disconnect(struct usb_interface *intf) struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_card *card; struct list_head *p; - bool was_shutdown; if (chip == (void *)-1L) return; card = chip->card; - down_write(&chip->shutdown_rwsem); - was_shutdown = chip->shutdown; - chip->shutdown = 1; - up_write(&chip->shutdown_rwsem); mutex_lock(®ister_mutex); - if (!was_shutdown) { + if (atomic_inc_return(&chip->shutdown) == 1) { struct snd_usb_stream *as; struct snd_usb_endpoint *ep; struct usb_mixer_interface *mixer; + /* wait until all pending tasks done; + * they are protected by snd_usb_lock_shutdown() + */ + wait_event(chip->shutdown_wait, + !atomic_read(&chip->usage_count)); snd_card_disconnect(card); /* release the pcm resources */ list_for_each_entry(as, &chip->pcm_list, list) { @@ -631,28 +633,50 @@ static void usb_audio_disconnect(struct usb_interface *intf) } } -#ifdef CONFIG_PM - -int snd_usb_autoresume(struct snd_usb_audio *chip) +/* lock the shutdown (disconnect) task and autoresume */ +int snd_usb_lock_shutdown(struct snd_usb_audio *chip) { - int err = -ENODEV; + int err; - down_read(&chip->shutdown_rwsem); - if (chip->probing || chip->in_pm) - err = 0; - else if (!chip->shutdown) - err = usb_autopm_get_interface(chip->pm_intf); - up_read(&chip->shutdown_rwsem); + atomic_inc(&chip->usage_count); + if (atomic_read(&chip->shutdown)) { + err = -EIO; + goto error; + } + err = snd_usb_autoresume(chip); + if (err < 0) + goto error; + return 0; + error: + if (atomic_dec_and_test(&chip->usage_count)) + wake_up(&chip->shutdown_wait); return err; } +/* autosuspend and unlock the shutdown */ +void snd_usb_unlock_shutdown(struct snd_usb_audio *chip) +{ + snd_usb_autosuspend(chip); + if (atomic_dec_and_test(&chip->usage_count)) + wake_up(&chip->shutdown_wait); +} + +#ifdef CONFIG_PM + +int snd_usb_autoresume(struct snd_usb_audio *chip) +{ + if (atomic_read(&chip->shutdown)) + return -EIO; + if (atomic_inc_return(&chip->active) == 1) + return usb_autopm_get_interface(chip->pm_intf); + return 0; +} + void snd_usb_autosuspend(struct snd_usb_audio *chip) { - down_read(&chip->shutdown_rwsem); - if (!chip->shutdown && !chip->probing && !chip->in_pm) + if (atomic_dec_and_test(&chip->active)) usb_autopm_put_interface(chip->pm_intf); - up_read(&chip->shutdown_rwsem); } static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) @@ -665,30 +689,20 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) if (chip == (void *)-1L) return 0; - if (!PMSG_IS_AUTO(message)) { + chip->autosuspended = !!PMSG_IS_AUTO(message); + if (!chip->autosuspended) snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); - if (!chip->num_suspended_intf++) { - list_for_each_entry(as, &chip->pcm_list, list) { - snd_pcm_suspend_all(as->pcm); - as->substream[0].need_setup_ep = - as->substream[1].need_setup_ep = true; - } - list_for_each(p, &chip->midi_list) { - snd_usbmidi_suspend(p); - } + if (!chip->num_suspended_intf++) { + list_for_each_entry(as, &chip->pcm_list, list) { + snd_pcm_suspend_all(as->pcm); + as->substream[0].need_setup_ep = + as->substream[1].need_setup_ep = true; } - } else { - /* - * otherwise we keep the rest of the system in the dark - * to keep this transparent - */ - if (!chip->num_suspended_intf++) - chip->autosuspended = 1; - } - - if (chip->num_suspended_intf == 1) + list_for_each(p, &chip->midi_list) + snd_usbmidi_suspend(p); list_for_each_entry(mixer, &chip->mixer_list, list) snd_usb_mixer_suspend(mixer); + } return 0; } @@ -705,7 +719,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) if (--chip->num_suspended_intf) return 0; - chip->in_pm = 1; + atomic_inc(&chip->active); /* avoid autopm */ /* * ALSA leaves material resumption to user space * we just notify and restart the mixers @@ -725,7 +739,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) chip->autosuspended = 0; err_out: - chip->in_pm = 0; + atomic_dec(&chip->active); /* allow autopm after this point */ return err; } |
