* [PATCH v2 2/6] ALSA: emu10k1: factor out snd_emu1010_load_dock_firmware()
2024-04-28 9:37 [PATCH v2 0/6] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
2024-04-28 9:37 ` [PATCH v2 1/6] ALSA: emu10k1: fix E-MU card dock presence monitoring Oswald Buddenhagen
@ 2024-04-28 9:37 ` Oswald Buddenhagen
2024-04-28 9:37 ` [PATCH v2 3/6] ALSA: emu10k1: move the whole GPIO event handling to the workqueue Oswald Buddenhagen
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Oswald Buddenhagen @ 2024-04-28 9:37 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
Pulled out of the next patch to improve its legibility.
As the function is now available, call it directly from
snd_emu10k1_emu1010_init(), thus making the MicroDock firmware loading
synchronous - there isn't really a reason not to. Note that this does
not affect the AudioDocks of rev1 cards, as these have no independent
power supplies, and thus come up only a while after the main card is
initialized.
As a drive-by, adjust the priorities of two messages to better reflect
their impact.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 66 +++++++++++++++++---------------
1 file changed, 36 insertions(+), 30 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 85f70368a27d..6265fc9ae260 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -732,11 +732,43 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
return snd_emu1010_load_firmware_entry(emu, *fw);
}
+static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
+{
+ u32 tmp, tmp2;
+ int err;
+
+ dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
+ /* Return to Audio Dock programming mode */
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
+ EMU_HANA_FPGA_CONFIG_AUDIODOCK);
+ err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
+ if (err < 0)
+ return;
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
+ dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
+ if ((tmp & 0x1f) != 0x15) {
+ /* FPGA failed to be programmed */
+ dev_err(emu->card->dev,
+ "emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n",
+ tmp);
+ return;
+ }
+ dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n");
+
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
+ dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
+
+ /* Allow DLL to settle, to sync clocking between 1010 and Dock */
+ msleep(10);
+}
+
static void emu1010_firmware_work(struct work_struct *work)
{
struct snd_emu10k1 *emu;
- u32 tmp, tmp2, reg;
- int err;
+ u32 reg;
emu = container_of(work, struct snd_emu10k1,
emu1010.firmware_work);
@@ -749,33 +781,7 @@ static void emu1010_firmware_work(struct work_struct *work)
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
/* Audio Dock attached */
- /* Return to Audio Dock programming mode */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware\n");
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
- EMU_HANA_FPGA_CONFIG_AUDIODOCK);
- err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
- if (err < 0)
- return;
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
- dev_info(emu->card->dev,
- "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
- if ((tmp & 0x1f) != 0x15) {
- /* FPGA failed to be programmed */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
- tmp);
- return;
- }
- dev_info(emu->card->dev,
- "emu1010: Audio Dock Firmware loaded\n");
- snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
- snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
- dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
- /* Sync clocking between 1010 and Dock */
- /* Allow DLL to settle */
- msleep(10);
+ snd_emu1010_load_dock_firmware(emu);
/* Unmute all. Default is muted after a firmware load */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
} else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) {
@@ -892,7 +898,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®);
dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE)
- schedule_work(&emu->emu1010.firmware_work);
+ snd_emu1010_load_dock_firmware(emu);
if (emu->card_capabilities->no_adat) {
emu->emu1010.optical_in = 0; /* IN_SPDIF */
emu->emu1010.optical_out = 0; /* OUT_SPDIF */
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 3/6] ALSA: emu10k1: move the whole GPIO event handling to the workqueue
2024-04-28 9:37 [PATCH v2 0/6] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
2024-04-28 9:37 ` [PATCH v2 1/6] ALSA: emu10k1: fix E-MU card dock presence monitoring Oswald Buddenhagen
2024-04-28 9:37 ` [PATCH v2 2/6] ALSA: emu10k1: factor out snd_emu1010_load_dock_firmware() Oswald Buddenhagen
@ 2024-04-28 9:37 ` Oswald Buddenhagen
2024-04-28 9:37 ` [PATCH v2 4/6] ALSA: emu10k1: use mutex for E-MU FPGA access locking Oswald Buddenhagen
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Oswald Buddenhagen @ 2024-04-28 9:37 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
The actual event processing was already done by workqueue items. We can
move the event dispatching there as well, rather than doing it already
in the interrupt handler callback.
This change has a rather profound "side effect" on the reliability of
the FPGA programming: once we enter programming mode, we must not issue
any snd_emu1010_fpga_{read,write}() calls until we're done, as these
would badly mess up the programming protocol. But exactly that would
happen when trying to program the dock, as that triggers GPIO interrupts
as a side effect. This is mitigated by deferring the actual interrupt
handling, as workqueue items are not re-entrant.
To avoid scheduling the dispatcher on non-events, we now explicitly
ignore GPIO IRQs triggered by "uninteresting" pins, which happens a lot
as a side effect of calling snd_emu1010_fpga_{read,write}().
Fixes: fbb64eedf5a3 ("ALSA: emu10k1: make E-MU dock monitoring interrupt-driven")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218584
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
include/sound/emu10k1.h | 3 +-
sound/pci/emu10k1/emu10k1.c | 3 +-
sound/pci/emu10k1/emu10k1_main.c | 56 ++++++++++++++++----------------
3 files changed, 30 insertions(+), 32 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 1af9e6819392..9cc10fab01a8 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1684,8 +1684,7 @@ struct snd_emu1010 {
unsigned int clock_fallback;
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 work_struct work;
};
struct snd_emu10k1 {
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index fe72e7d77241..dadeda7758ce 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -189,8 +189,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);
+ cancel_work_sync(&emu->emu1010.work);
snd_ac97_suspend(emu->ac97);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 6265fc9ae260..86eaf5963502 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -765,19 +765,10 @@ static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
msleep(10);
}
-static void emu1010_firmware_work(struct work_struct *work)
+static void emu1010_dock_event(struct snd_emu10k1 *emu)
{
- struct snd_emu10k1 *emu;
u32 reg;
- emu = container_of(work, struct snd_emu10k1,
- emu1010.firmware_work);
- if (emu->card->shutdown)
- return;
-#ifdef CONFIG_PM_SLEEP
- if (emu->suspend)
- return;
-#endif
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
/* Audio Dock attached */
@@ -792,43 +783,54 @@ static void emu1010_firmware_work(struct work_struct *work)
}
}
-static void emu1010_clock_work(struct work_struct *work)
+static void emu1010_clock_event(struct snd_emu10k1 *emu)
{
- 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
-
spin_lock_irq(&emu->reg_lock);
// 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);
spin_unlock_irq(&emu->reg_lock);
snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0);
snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
}
-static void emu1010_interrupt(struct snd_emu10k1 *emu)
+static void emu1010_work(struct work_struct *work)
{
+ struct snd_emu10k1 *emu;
u32 sts;
+ emu = container_of(work, struct snd_emu10k1, emu1010.work);
+ if (emu->card->shutdown)
+ return;
+#ifdef CONFIG_PM_SLEEP
+ if (emu->suspend)
+ return;
+#endif
+
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
// The distinction of the IRQ status bits is unreliable,
// so we dispatch later based on option card status.
if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
- schedule_work(&emu->emu1010.firmware_work);
+ emu1010_dock_event(emu);
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
- schedule_work(&emu->emu1010.clock_work);
+ emu1010_clock_event(emu);
+}
+
+static void emu1010_interrupt(struct snd_emu10k1 *emu)
+{
+ // We get an interrupt on each GPIO input pin change, but we
+ // care only about the ones triggered by the dedicated pin.
+ u16 sts = inw(emu->port + A_GPIO);
+ u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000;
+ if (!(sts & bit))
+ return;
+
+ schedule_work(&emu->emu1010.work);
}
/*
@@ -969,8 +971,7 @@ static void snd_emu10k1_free(struct snd_card *card)
/* Disable 48Volt power to Audio Dock */
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
}
- cancel_work_sync(&emu->emu1010.firmware_work);
- cancel_work_sync(&emu->emu1010.clock_work);
+ cancel_work_sync(&emu->emu1010.work);
release_firmware(emu->firmware);
release_firmware(emu->dock_fw);
snd_util_memhdr_free(emu->memhdr);
@@ -1549,8 +1550,7 @@ int snd_emu10k1_create(struct snd_card *card,
emu->irq = -1;
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);
+ INIT_WORK(&emu->emu1010.work, emu1010_work);
/* read revision & serial */
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 4/6] ALSA: emu10k1: use mutex for E-MU FPGA access locking
2024-04-28 9:37 [PATCH v2 0/6] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (2 preceding siblings ...)
2024-04-28 9:37 ` [PATCH v2 3/6] ALSA: emu10k1: move the whole GPIO event handling to the workqueue Oswald Buddenhagen
@ 2024-04-28 9:37 ` Oswald Buddenhagen
2024-04-28 9:37 ` [PATCH v2 5/6] ALSA: emu10k1: fix E-MU dock initialization Oswald Buddenhagen
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Oswald Buddenhagen @ 2024-04-28 9:37 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
The FPGA access through the GPIO port does not interfere with other
sound processor register access, so there is no need to subject it to
emu_lock. And after moving all FPGA access out of the interrupt handler,
it does not need to be IRQ-safe, either.
What's more, attaching the dock causes a firmware upload, which takes
several seconds. We really don't want to disable IRQs for this long, and
even less also have someone else spin with IRQs disabled waiting for us.
Therefore, use a mutex for FPGA access locking.
This makes the code somewhat more noisy, as we need to wrap bigger
sections into the mutex, as it needs to enclose the spinlocks.
The latter has the "side effect" of fixing dock FPGA programming in a
corner case: a really badly timed mixer access right between entering
FPGA programming mode and uploading the netlist would mess up the
protocol.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
include/sound/emu10k1.h | 4 +++
sound/pci/emu10k1/emu10k1_main.c | 19 +++++++++---
sound/pci/emu10k1/emumixer.c | 18 ++++++++----
sound/pci/emu10k1/emuproc.c | 9 ++++++
sound/pci/emu10k1/io.c | 50 ++++++++++++++------------------
5 files changed, 62 insertions(+), 38 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 9cc10fab01a8..234b5baea69c 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1685,6 +1685,7 @@ struct snd_emu1010 {
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
struct work_struct work;
+ struct mutex lock;
};
struct snd_emu10k1 {
@@ -1833,6 +1834,9 @@ unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg,
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
+static inline void snd_emu1010_fpga_lock(struct snd_emu10k1 *emu) { mutex_lock(&emu->emu1010.lock); };
+static inline void snd_emu1010_fpga_unlock(struct snd_emu10k1 *emu) { mutex_unlock(&emu->emu1010.lock); };
+void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value);
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value);
void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 86eaf5963502..1a2905e8672b 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -810,15 +810,19 @@ static void emu1010_work(struct work_struct *work)
return;
#endif
+ snd_emu1010_fpga_lock(emu);
+
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
// The distinction of the IRQ status bits is unreliable,
// so we dispatch later based on option card status.
if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
emu1010_dock_event(emu);
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
emu1010_clock_event(emu);
+
+ snd_emu1010_fpga_unlock(emu);
}
static void emu1010_interrupt(struct snd_emu10k1 *emu)
@@ -852,6 +856,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
* Proper init follows in snd_emu10k1_init(). */
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
+ snd_emu1010_fpga_lock(emu);
+
/* Disable 48Volt power to Audio Dock */
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
@@ -877,17 +883,18 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
if (err < 0) {
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
- return err;
+ goto fail;
}
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®);
if ((reg & 0x3f) != 0x15) {
/* FPGA failed to be programmed */
dev_info(emu->card->dev,
"emu1010: Loading Hana Firmware file failed, reg = 0x%x\n",
reg);
- return -ENODEV;
+ err = -ENODEV;
+ goto fail;
}
dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n");
@@ -947,7 +954,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
// so it is safe to simply enable the outputs.
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
- return 0;
+fail:
+ snd_emu1010_fpga_unlock(emu);
+ return err;
}
/*
* Create the EMU10K1 instance
@@ -969,9 +978,10 @@ static void snd_emu10k1_free(struct snd_card *card)
}
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
/* Disable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DOCK_PWR, 0);
}
cancel_work_sync(&emu->emu1010.work);
+ mutex_destroy(&emu->emu1010.lock);
release_firmware(emu->firmware);
release_firmware(emu->dock_fw);
snd_util_memhdr_free(emu->memhdr);
@@ -1551,6 +1561,7 @@ int snd_emu10k1_create(struct snd_card *card,
emu->synth = NULL;
emu->get_synth_voice = NULL;
INIT_WORK(&emu->emu1010.work, emu1010_work);
+ mutex_init(&emu->emu1010.lock);
/* 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 0a32ea53d8c6..05b98d9b547b 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -661,7 +661,9 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
change = (emu->emu1010.output_source[channel] != val);
if (change) {
emu->emu1010.output_source[channel] = val;
+ snd_emu1010_fpga_lock(emu);
snd_emu1010_output_source_apply(emu, channel, val);
+ snd_emu1010_fpga_unlock(emu);
}
return change;
}
@@ -705,7 +707,9 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
change = (emu->emu1010.input_source[channel] != val);
if (change) {
emu->emu1010.input_source[channel] = val;
+ snd_emu1010_fpga_lock(emu);
snd_emu1010_input_source_apply(emu, channel, val);
+ snd_emu1010_fpga_unlock(emu);
}
return change;
}
@@ -774,7 +778,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
cache = cache & ~mask;
change = (cache != emu->emu1010.adc_pads);
if (change) {
- snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_ADC_PADS, cache );
emu->emu1010.adc_pads = cache;
}
@@ -832,7 +836,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
cache = cache & ~mask;
change = (cache != emu->emu1010.dac_pads);
if (change) {
- snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DAC_PADS, cache );
emu->emu1010.dac_pads = cache;
}
@@ -980,6 +984,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
val = ucontrol->value.enumerated.item[0] ;
if (val >= emu_ci->num)
return -EINVAL;
+ snd_emu1010_fpga_lock(emu);
spin_lock_irq(&emu->reg_lock);
change = (emu->emu1010.clock_source != val);
if (change) {
@@ -996,6 +1001,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
} else {
spin_unlock_irq(&emu->reg_lock);
}
+ snd_emu1010_fpga_unlock(emu);
return change;
}
@@ -1041,7 +1047,7 @@ static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
change = (emu->emu1010.clock_fallback != val);
if (change) {
emu->emu1010.clock_fallback = val;
- snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DEFCLOCK, 1 - val);
}
return change;
}
@@ -1093,7 +1099,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
emu->emu1010.optical_out = val;
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
- snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
}
return change;
}
@@ -1144,7 +1150,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
emu->emu1010.optical_in = val;
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
- snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
}
return change;
}
@@ -2323,7 +2329,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
for (i = 0; i < emu_ri->n_outs; i++)
emu->emu1010.output_source[i] =
emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
+ snd_emu1010_fpga_lock(emu);
snd_emu1010_apply_sources(emu);
+ snd_emu1010_fpga_unlock(emu);
kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
err = snd_ctl_add(card, kctl);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index 2f80fd91017c..737c28d31b41 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -165,6 +165,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
u32 value2;
if (emu->card_capabilities->emu_model) {
+ snd_emu1010_fpga_lock(emu);
+
// This represents the S/PDIF lock status on 0404b, which is
// kinda weird and unhelpful, because monitoring it via IRQ is
// impractical (one gets an IRQ flood as long as it is desynced).
@@ -197,6 +199,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n",
value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer",
value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : "");
+
+ snd_emu1010_fpga_unlock(emu);
} else {
snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS);
snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
@@ -458,6 +462,9 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
struct snd_emu10k1 *emu = entry->private_data;
u32 value;
int i;
+
+ snd_emu1010_fpga_lock(emu);
+
snd_iprintf(buffer, "EMU1010 Registers:\n\n");
for(i = 0; i < 0x40; i+=1) {
@@ -496,6 +503,8 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
snd_emu_proc_emu1010_link_read(emu, buffer, 0x701);
}
}
+
+ snd_emu1010_fpga_unlock(emu);
}
static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry,
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 74df2330015f..f3260a81e47b 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -289,71 +289,63 @@ static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
+ if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
+ return;
snd_emu1010_fpga_write_locked(emu, reg, value);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
-static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *value)
+void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value)
+{
+ snd_emu1010_fpga_lock(emu);
+ snd_emu1010_fpga_write_locked(emu, reg, value);
+ snd_emu1010_fpga_unlock(emu);
+}
+
+void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
{
// The higest input pin is used as the designated interrupt trigger,
// so it needs to be masked out.
// But note that any other input pin change will also cause an IRQ,
// so using this function often causes an IRQ as a side effect.
u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f;
+
+ if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
+ return;
if (snd_BUG_ON(reg > 0x3f))
return;
reg += 0x40; /* 0x40 upwards are registers. */
outw(reg, emu->port + A_GPIO);
udelay(10);
outw(reg | 0x80, emu->port + A_GPIO); /* High bit clocks the value into the fpga. */
udelay(10);
*value = ((inw(emu->port + A_GPIO) >> 8) & mask);
}
-void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
- snd_emu1010_fpga_read_locked(emu, reg, value);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
-}
-
/* Each Destination has one and only one Source,
* but one Source can feed any number of Destinations simultaneously.
*/
void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src)
{
- unsigned long flags;
-
if (snd_BUG_ON(dst & ~0x71f))
return;
if (snd_BUG_ON(src & ~0x71f))
return;
- spin_lock_irqsave(&emu->emu_lock, flags);
- snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8);
- snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f);
- snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCHI, src >> 8);
- snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCLO, src & 0x1f);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f);
+ snd_emu1010_fpga_write(emu, EMU_HANA_SRCHI, src >> 8);
+ snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f);
}
u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst)
{
- unsigned long flags;
u32 hi, lo;
if (snd_BUG_ON(dst & ~0x71f))
return 0;
- spin_lock_irqsave(&emu->emu_lock, flags);
- snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8);
- snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f);
- snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCHI, &hi);
- snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCLO, &lo);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f);
+ snd_emu1010_fpga_read(emu, EMU_HANA_SRCHI, &hi);
+ snd_emu1010_fpga_read(emu, EMU_HANA_SRCLO, &lo);
return (hi << 8) | lo;
}
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread