From: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
To: alsa-devel@alsa-project.org
Cc: Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>
Subject: [PATCH 2/2] ALSA: emu10k1: track loss of external clock on E-MU cards
Date: Mon, 10 Jul 2023 08:59:56 +0200 [thread overview]
Message-ID: <20230710065956.1246364-2-oswald.buddenhagen@gmx.de> (raw)
In-Reply-To: <20230710065956.1246364-1-oswald.buddenhagen@gmx.de>
This uses IRQs to track spontaneous changes to the word clock source
register.
FWIW, that this can happen in the first place is the reason why it is
futile to lock the clock source mixer setting while the device is open -
we can't consistently control the rate anyway. Though arguably, we
should reset any open streams when that happens, as they become
corrupted anyway.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
FIXME? while i'm not sure, i think this won't notice seamless switches
between 44.1 and 48 kHz. assuming that's the case, this seems like a
minor issue: firstly, just about nothing actually produces such a
seamless switch - my only device that can even do that is the e-mu card
itself, but the driver disrupts that by temporarily muting the output.
secondly, the user is unlikely to select an external source before
setting it up properly. and the easy workaround is actually never doing
that.
regardless, to actually test that i'd need a second e-mu card.
---
include/sound/emu10k1.h | 5 +++++
sound/pci/emu10k1/emu10k1.c | 1 +
sound/pci/emu10k1/emu10k1_main.c | 32 +++++++++++++++++++++++++++++++-
sound/pci/emu10k1/emumixer.c | 4 ++--
4 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 43c097952c3c..7c55a8244747 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -992,6 +992,9 @@ SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00) /* This sets the capture PCM
#define EMU_HANA_WCLOCK_4X 0x10
#define EMU_HANA_WCLOCK_MULT_RESERVED 0x18
+// If the selected external clock source is/becomes invalid or incompatible
+// with the clock multiplier, the clock source is reset to this value, and
+// a WCLK_CHANGED interrupt is raised.
#define EMU_HANA_DEFCLOCK 0x06 /* 000000x 1 bits Default Word Clock */
#define EMU_HANA_DEFCLOCK_48K 0x00
#define EMU_HANA_DEFCLOCK_44_1K 0x01
@@ -1679,6 +1682,7 @@ struct snd_emu1010 {
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
struct work_struct firmware_work;
+ struct work_struct clock_work;
};
struct snd_emu10k1 {
@@ -1753,6 +1757,7 @@ struct snd_emu10k1 {
struct snd_kcontrol *ctl_efx_send_routing;
struct snd_kcontrol *ctl_efx_send_volume;
struct snd_kcontrol *ctl_efx_attn;
+ struct snd_kcontrol *ctl_clock_source;
void (*hwvol_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
void (*capture_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 1a13c086e86c..421053569aa0 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -192,6 +192,7 @@ static int snd_emu10k1_suspend(struct device *dev)
emu->suspend = 1;
cancel_work_sync(&emu->emu1010.firmware_work);
+ cancel_work_sync(&emu->emu1010.clock_work);
snd_ac97_suspend(emu->ac97);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 661164dbf547..7c114fe31831 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -790,6 +790,32 @@ static void emu1010_firmware_work(struct work_struct *work)
}
}
+static void emu1010_clock_work(struct work_struct *work)
+{
+ struct snd_emu10k1 *emu;
+ struct snd_ctl_elem_id id;
+
+ emu = container_of(work, struct snd_emu10k1,
+ emu1010.clock_work);
+ if (emu->card->shutdown)
+ return;
+#ifdef CONFIG_PM_SLEEP
+ if (emu->suspend)
+ return;
+#endif
+
+ // We consider this a mixer setting, so use the mixer's lock
+ down_write(&emu->card->controls_rwsem);
+ // This is the only thing that can actually happen.
+ emu->emu1010.clock_source = emu->emu1010.clock_fallback;
+ emu->emu1010.wclock = 1 - emu->emu1010.clock_source;
+ snd_emu1010_update_clock(emu);
+ downgrade_write(&emu->card->controls_rwsem);
+ snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0);
+ snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
+ up_read(&emu->card->controls_rwsem);
+}
+
static void emu1010_interrupt(struct snd_emu10k1 *emu)
{
u32 sts;
@@ -803,6 +829,8 @@ static void emu1010_interrupt(struct snd_emu10k1 *emu)
} else if (sts & EMU_HANA_IRQ_DOCK) {
schedule_work(&emu->emu1010.firmware_work);
}
+ if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
+ schedule_work(&emu->emu1010.clock_work);
}
/*
@@ -902,7 +930,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
emu->gpio_interrupt = emu1010_interrupt;
// Note: The Audigy INTE is set later
snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE,
- EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST);
+ EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST | EMU_HANA_IRQ_WCLK_CHANGED);
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); // Clear pending IRQs
emu->emu1010.clock_source = 1; /* 48000 */
@@ -944,6 +972,7 @@ static void snd_emu10k1_free(struct snd_card *card)
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
}
cancel_work_sync(&emu->emu1010.firmware_work);
+ cancel_work_sync(&emu->emu1010.clock_work);
release_firmware(emu->firmware);
release_firmware(emu->dock_fw);
snd_util_memhdr_free(emu->memhdr);
@@ -1523,6 +1552,7 @@ int snd_emu10k1_create(struct snd_card *card,
emu->synth = NULL;
emu->get_synth_voice = NULL;
INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
+ INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work);
/* read revision & serial */
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index f9500cd50a4b..a9302db535d9 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -2342,8 +2342,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
snd_emu1010_apply_sources(emu);
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_clock_source, emu));
+ kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
+ err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
err = snd_ctl_add(card,
--
2.40.0.152.g15d061e6df
next prev parent reply other threads:[~2023-07-10 7:02 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-10 6:59 [PATCH 1/2] ALSA: emu10k1: make E-MU dock monitoring interrupt-driven Oswald Buddenhagen
2023-07-10 6:59 ` Oswald Buddenhagen [this message]
2023-07-10 15:05 ` [PATCH 2/2] ALSA: emu10k1: track loss of external clock on E-MU cards Takashi Iwai
2023-07-10 17:34 ` Oswald Buddenhagen
2023-07-11 5:28 ` Takashi Iwai
2023-07-11 10:11 ` Oswald Buddenhagen
2023-07-11 11:14 ` Takashi Iwai
2023-07-10 14:57 ` [PATCH 1/2] ALSA: emu10k1: make E-MU dock monitoring interrupt-driven Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230710065956.1246364-2-oswald.buddenhagen@gmx.de \
--to=oswald.buddenhagen@gmx.de \
--cc=alsa-devel@alsa-project.org \
--cc=perex@perex.cz \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox