diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-19 13:41:32 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-19 13:41:32 -0700 |
commit | f4c80d5a16eb4b08a0d9ade154af1ebdc63f5752 (patch) | |
tree | 5334acabf48210285333bc80d4a3e326efb36750 /sound/firewire/oxfw/oxfw.c | |
parent | 7afd16f882887c9adc69cd1794f5e57777723217 (diff) | |
parent | 17e1717c11a34f9b0956e33e0c4a4e4ae8c51a57 (diff) |
Merge tag 'sound-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"This time was again a relatively calm development cycle; most of
updates are about drivers, and no radical changes are seen in any core
code. Here are some highlights:
ALSA core:
- Continued hardening of ALSA hrtimer
- A few leak fixes in timer interface
- Fix poll error handling in PCM and compress
- Add error propagation in compress API
- Removal of dead rtctimer driver
HD-audio:
- Native ELD notify support for i915 HDMI
- Realtek ALC234 & co support
- Code refactoring to standardize chmap support
- Continued development for SKL HDMI core support
Firewire:
- Apply delayed card registration to all drivers
- Improved / stabilized the handling of PCM stream start / stop
- Add tracepoints to dump a part of isochronous packet data
- Fixed incoming/outgoing packet parameter usages
- Add support for M-Audio profire series
USB-audio:
- Fixes for UAC2 clock source
- SS+ support
- Workaround for oft-seen repeated sample rate read errors
ASoC:
- Further slow progress on the topology code
- Substantial updates and improvements for the da7219, es8328,
fsl-ssi, Intel and rcar drivers.
- Compress error handling in WM ADSP driver"
* tag 'sound-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (177 commits)
ALSA: firewire-lib: change a member of event structure to suppress sparse wanings to bool type
sound: oss: Use setup_timer and mod_timer.
ASoC: hdac_hdmi: Remove the unused 'timeout' variable
ASoC: fsl_ssi: Fix channel slipping on capture (or playback) restart in full duplex.
ASoC: fsl_ssi: Fix channel slipping in Playback at startup
ASoC: fsl_ssi: Fix samples being dropped at Playback startup
ASoC: fsl_ssi: Save a dev reference for dev_err() purpose.
ASoC: fsl_ssi: The IPG/5 limitation concerns the bitclk, not the sysclk.
ASoC: fsl_ssi: Real hardware channels max number is 32
ASoC: pcm5102a: Add support for PCM5102A codec
ASoC: hdac_hdmi: add link management
ASoC: Intel: Skylake: add link management
ALSA: hdac: add link pm and ref counting
ALSA: au88x0: Fix zero clear of stream->resources
ASoC: rt298: Add DMI match for Broxton-P reference platform
ASoC: rt298: fix null deref on acpi driver data
ASoC: dapm: deprecate MICBIAS widget type
ALSA: firewire-lib: drop skip argument from helper functions to queue a packet
ALSA: firewire-lib: add context information to tracepoints
ALSA: firewire-lib: permit to flush queued packets only in process context for better PCM period granularity
...
Diffstat (limited to 'sound/firewire/oxfw/oxfw.c')
-rw-r--r-- | sound/firewire/oxfw/oxfw.c | 151 |
1 files changed, 98 insertions, 53 deletions
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index abedc2207261..e629b88f7d93 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -118,15 +118,8 @@ end: return err; } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void oxfw_card_free(struct snd_card *card) +static void oxfw_free(struct snd_oxfw *oxfw) { - struct snd_oxfw *oxfw = card->private_data; unsigned int i; snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); @@ -144,6 +137,17 @@ static void oxfw_card_free(struct snd_card *card) mutex_destroy(&oxfw->mutex); } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ +static void oxfw_card_free(struct snd_card *card) +{ + oxfw_free(card->private_data); +} + static int detect_quirks(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); @@ -205,41 +209,39 @@ static int detect_quirks(struct snd_oxfw *oxfw) return 0; } -static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) +static void do_registration(struct work_struct *work) { - struct snd_card *card; - struct snd_oxfw *oxfw; + struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work); int err; - if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) - return -ENODEV; + if (oxfw->registered) + return; - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(*oxfw), &card); + err = snd_card_new(&oxfw->unit->device, -1, NULL, THIS_MODULE, 0, + &oxfw->card); if (err < 0) - return err; + return; - card->private_free = oxfw_card_free; - oxfw = card->private_data; - oxfw->card = card; - mutex_init(&oxfw->mutex); - oxfw->unit = fw_unit_get(unit); - oxfw->entry = entry; - spin_lock_init(&oxfw->lock); - init_waitqueue_head(&oxfw->hwdep_wait); + err = name_card(oxfw); + if (err < 0) + goto error; - err = snd_oxfw_stream_discover(oxfw); + err = detect_quirks(oxfw); if (err < 0) goto error; - err = name_card(oxfw); + err = snd_oxfw_stream_discover(oxfw); if (err < 0) goto error; - err = detect_quirks(oxfw); + err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream); if (err < 0) goto error; + if (oxfw->has_output) { + err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream); + if (err < 0) + goto error; + } err = snd_oxfw_create_pcm(oxfw); if (err < 0) @@ -255,54 +257,97 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream); + err = snd_card_register(oxfw->card); if (err < 0) goto error; - if (oxfw->has_output) { - err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream); - if (err < 0) - goto error; - } - err = snd_card_register(card); - if (err < 0) { - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - goto error; - } + /* + * After registered, oxfw instance can be released corresponding to + * releasing the sound card instance. + */ + oxfw->card->private_free = oxfw_card_free; + oxfw->card->private_data = oxfw; + oxfw->registered = true; + + return; +error: + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); + snd_card_free(oxfw->card); + dev_info(&oxfw->unit->device, + "Sound card registration failed: %d\n", err); +} + +static int oxfw_probe(struct fw_unit *unit, + const struct ieee1394_device_id *entry) +{ + struct snd_oxfw *oxfw; + + if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) + return -ENODEV; + + /* Allocate this independent of sound card instance. */ + oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL); + if (oxfw == NULL) + return -ENOMEM; + + oxfw->entry = entry; + oxfw->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, oxfw); + mutex_init(&oxfw->mutex); + spin_lock_init(&oxfw->lock); + init_waitqueue_head(&oxfw->hwdep_wait); + + /* Allocate and register this sound card later. */ + INIT_DEFERRABLE_WORK(&oxfw->dwork, do_registration); + snd_fw_schedule_registration(unit, &oxfw->dwork); + return 0; -error: - snd_card_free(card); - return err; } static void oxfw_bus_reset(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); + if (!oxfw->registered) + snd_fw_schedule_registration(unit, &oxfw->dwork); + fcp_bus_reset(oxfw->unit); - mutex_lock(&oxfw->mutex); + if (oxfw->registered) { + mutex_lock(&oxfw->mutex); - snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream); + snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream); - mutex_unlock(&oxfw->mutex); + mutex_unlock(&oxfw->mutex); - if (oxfw->entry->vendor_id == OUI_STANTON) - snd_oxfw_scs1x_update(oxfw); + if (oxfw->entry->vendor_id == OUI_STANTON) + snd_oxfw_scs1x_update(oxfw); + } } static void oxfw_remove(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(oxfw->card); + /* + * Confirm to stop the work for registration before the sound card is + * going to be released. The work is not scheduled again because bus + * reset handler is not called anymore. + */ + cancel_delayed_work_sync(&oxfw->dwork); + + if (oxfw->registered) { + /* No need to wait for releasing card object in this context. */ + snd_card_free_when_closed(oxfw->card); + } else { + /* Don't forget this case. */ + oxfw_free(oxfw); + } } static const struct compat_info griffin_firewave = { |