Skip to content

Commit f848337

Browse files
ossilatortiwai
authored andcommitted
ALSA: emu10k1: move the whole GPIO event handling to the workqueue
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: fbb64ee ("ALSA: emu10k1: make E-MU dock monitoring interrupt-driven") Link: https://bugzilla.kernel.org/show_bug.cgi?id=218584 Signed-off-by: Oswald Buddenhagen <[email protected]> Signed-off-by: Takashi Iwai <[email protected]> Message-ID: <[email protected]>
1 parent 28deafd commit f848337

File tree

3 files changed

+30
-32
lines changed

3 files changed

+30
-32
lines changed

include/sound/emu10k1.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,8 +1684,7 @@ struct snd_emu1010 {
16841684
unsigned int clock_fallback;
16851685
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
16861686
unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
1687-
struct work_struct firmware_work;
1688-
struct work_struct clock_work;
1687+
struct work_struct work;
16891688
};
16901689

16911690
struct snd_emu10k1 {

sound/pci/emu10k1/emu10k1.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,7 @@ static int snd_emu10k1_suspend(struct device *dev)
189189

190190
emu->suspend = 1;
191191

192-
cancel_work_sync(&emu->emu1010.firmware_work);
193-
cancel_work_sync(&emu->emu1010.clock_work);
192+
cancel_work_sync(&emu->emu1010.work);
194193

195194
snd_ac97_suspend(emu->ac97);
196195

sound/pci/emu10k1/emu10k1_main.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -765,19 +765,10 @@ static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
765765
msleep(10);
766766
}
767767

768-
static void emu1010_firmware_work(struct work_struct *work)
768+
static void emu1010_dock_event(struct snd_emu10k1 *emu)
769769
{
770-
struct snd_emu10k1 *emu;
771770
u32 reg;
772771

773-
emu = container_of(work, struct snd_emu10k1,
774-
emu1010.firmware_work);
775-
if (emu->card->shutdown)
776-
return;
777-
#ifdef CONFIG_PM_SLEEP
778-
if (emu->suspend)
779-
return;
780-
#endif
781772
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
782773
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
783774
/* Audio Dock attached */
@@ -792,20 +783,10 @@ static void emu1010_firmware_work(struct work_struct *work)
792783
}
793784
}
794785

795-
static void emu1010_clock_work(struct work_struct *work)
786+
static void emu1010_clock_event(struct snd_emu10k1 *emu)
796787
{
797-
struct snd_emu10k1 *emu;
798788
struct snd_ctl_elem_id id;
799789

800-
emu = container_of(work, struct snd_emu10k1,
801-
emu1010.clock_work);
802-
if (emu->card->shutdown)
803-
return;
804-
#ifdef CONFIG_PM_SLEEP
805-
if (emu->suspend)
806-
return;
807-
#endif
808-
809790
spin_lock_irq(&emu->reg_lock);
810791
// This is the only thing that can actually happen.
811792
emu->emu1010.clock_source = emu->emu1010.clock_fallback;
@@ -816,19 +797,40 @@ static void emu1010_clock_work(struct work_struct *work)
816797
snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
817798
}
818799

819-
static void emu1010_interrupt(struct snd_emu10k1 *emu)
800+
static void emu1010_work(struct work_struct *work)
820801
{
802+
struct snd_emu10k1 *emu;
821803
u32 sts;
822804

805+
emu = container_of(work, struct snd_emu10k1, emu1010.work);
806+
if (emu->card->shutdown)
807+
return;
808+
#ifdef CONFIG_PM_SLEEP
809+
if (emu->suspend)
810+
return;
811+
#endif
812+
823813
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
824814

825815
// The distinction of the IRQ status bits is unreliable,
826816
// so we dispatch later based on option card status.
827817
if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
828-
schedule_work(&emu->emu1010.firmware_work);
818+
emu1010_dock_event(emu);
829819

830820
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
831-
schedule_work(&emu->emu1010.clock_work);
821+
emu1010_clock_event(emu);
822+
}
823+
824+
static void emu1010_interrupt(struct snd_emu10k1 *emu)
825+
{
826+
// We get an interrupt on each GPIO input pin change, but we
827+
// care only about the ones triggered by the dedicated pin.
828+
u16 sts = inw(emu->port + A_GPIO);
829+
u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000;
830+
if (!(sts & bit))
831+
return;
832+
833+
schedule_work(&emu->emu1010.work);
832834
}
833835

834836
/*
@@ -969,8 +971,7 @@ static void snd_emu10k1_free(struct snd_card *card)
969971
/* Disable 48Volt power to Audio Dock */
970972
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
971973
}
972-
cancel_work_sync(&emu->emu1010.firmware_work);
973-
cancel_work_sync(&emu->emu1010.clock_work);
974+
cancel_work_sync(&emu->emu1010.work);
974975
release_firmware(emu->firmware);
975976
release_firmware(emu->dock_fw);
976977
snd_util_memhdr_free(emu->memhdr);
@@ -1549,8 +1550,7 @@ int snd_emu10k1_create(struct snd_card *card,
15491550
emu->irq = -1;
15501551
emu->synth = NULL;
15511552
emu->get_synth_voice = NULL;
1552-
INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
1553-
INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work);
1553+
INIT_WORK(&emu->emu1010.work, emu1010_work);
15541554
/* read revision & serial */
15551555
emu->revision = pci->revision;
15561556
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);

0 commit comments

Comments
 (0)