Commit fbb64eed authored by Oswald Buddenhagen's avatar Oswald Buddenhagen Committed by Takashi Iwai
Browse files

ALSA: emu10k1: make E-MU dock monitoring interrupt-driven

parent 7d43f51e
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1678,8 +1678,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 delayed_work firmware_work;
	u32 last_reg;
	struct work_struct firmware_work;
};

struct snd_emu10k1 {
@@ -1761,6 +1760,7 @@ struct snd_emu10k1 {
	void (*capture_efx_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
	void (*spdif_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
	void (*dsp_interrupt)(struct snd_emu10k1 *emu);
	void (*gpio_interrupt)(struct snd_emu10k1 *emu);
	void (*p16v_interrupt)(struct snd_emu10k1 *emu);

	struct snd_pcm_substream *pcm_capture_substream;
+1 −7
Original line number Diff line number Diff line
@@ -176,9 +176,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
	if (err < 0)
		return err;

	if (emu->card_capabilities->emu_model)
		schedule_delayed_work(&emu->emu1010.firmware_work, 0);

	pci_set_drvdata(pci, card);
	dev++;
	return 0;
@@ -194,7 +191,7 @@ static int snd_emu10k1_suspend(struct device *dev)

	emu->suspend = 1;

	cancel_delayed_work_sync(&emu->emu1010.firmware_work);
	cancel_work_sync(&emu->emu1010.firmware_work);

	snd_ac97_suspend(emu->ac97);

@@ -224,9 +221,6 @@ static int snd_emu10k1_resume(struct device *dev)

	snd_power_change_state(card, SNDRV_CTL_POWER_D0);

	if (emu->card_capabilities->emu_model)
		schedule_delayed_work(&emu->emu1010.firmware_work, 0);

	return 0;
}

+28 −23
Original line number Diff line number Diff line
@@ -391,6 +391,9 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
	}
#endif

	if (emu->card_capabilities->emu_model)
		snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE | INTE_A_GPIOENABLE);
	else
		snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
}

@@ -745,14 +748,13 @@ static void emu1010_firmware_work(struct work_struct *work)
	int err;

	emu = container_of(work, struct snd_emu10k1,
			   emu1010.firmware_work.work);
			   emu1010.firmware_work);
	if (emu->card->shutdown)
		return;
#ifdef CONFIG_PM_SLEEP
	if (emu->suspend)
		return;
#endif
	snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */
	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
	if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
		/* Audio Dock attached */
@@ -763,13 +765,8 @@ static void emu1010_firmware_work(struct work_struct *work)
				       EMU_HANA_FPGA_CONFIG_AUDIODOCK);
		err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
		if (err < 0)
			goto next;

			return;
		snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp);
		dev_info(emu->card->dev,
			 "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", tmp);
		/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
		snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
		dev_info(emu->card->dev,
			 "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
@@ -778,7 +775,7 @@ static void emu1010_firmware_work(struct work_struct *work)
			dev_info(emu->card->dev,
				 "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
				 tmp);
			goto next;
			return;
		}
		dev_info(emu->card->dev,
			 "emu1010: Audio Dock Firmware loaded\n");
@@ -790,18 +787,22 @@ static void emu1010_firmware_work(struct work_struct *work)
		msleep(10);
		/* Unmute all. Default is muted after a firmware load */
		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
	} else if (!reg && emu->emu1010.last_reg) {
	}
}

static void emu1010_interrupt(struct snd_emu10k1 *emu)
{
	u32 sts;

	snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
	if (sts & EMU_HANA_IRQ_DOCK_LOST) {
		/* Audio Dock removed */
		dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
		/* The hardware auto-mutes all, so we unmute again */
		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
	} else if (sts & EMU_HANA_IRQ_DOCK) {
		schedule_work(&emu->emu1010.firmware_work);
	}

 next:
	emu->emu1010.last_reg = reg;
	if (!emu->card->shutdown)
		schedule_delayed_work(&emu->emu1010.firmware_work,
				      msecs_to_jiffies(1000));
}

/*
@@ -870,6 +871,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)

	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
	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);
	if (emu->card_capabilities->no_adat) {
		emu->emu1010.optical_in = 0; /* IN_SPDIF */
		emu->emu1010.optical_out = 0; /* OUT_SPDIF */
@@ -895,10 +898,12 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
	/* MIDI routing */
	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, EMU_HANA_MIDI_INA_FROM_HAMOA | EMU_HANA_MIDI_INB_FROM_DOCK2);
	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, EMU_HANA_MIDI_OUT_DOCK2 | EMU_HANA_MIDI_OUT_SYNC2);
	/* IRQ Enable: All on */
	/* snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x0f); */
	/* IRQ Enable: All off */
	snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);

	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);
	snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);  // Clear pending IRQs

	emu->emu1010.clock_source = 1;  /* 48000 */
	emu->emu1010.clock_fallback = 1;  /* 48000 */
@@ -938,7 +943,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_delayed_work_sync(&emu->emu1010.firmware_work);
	cancel_work_sync(&emu->emu1010.firmware_work);
	release_firmware(emu->firmware);
	release_firmware(emu->dock_fw);
	snd_util_memhdr_free(emu->memhdr);
@@ -1517,7 +1522,7 @@ int snd_emu10k1_create(struct snd_card *card,
	emu->irq = -1;
	emu->synth = NULL;
	emu->get_synth_voice = NULL;
	INIT_DELAYED_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
	INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
	/* read revision & serial */
	emu->revision = pci->revision;
	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
+2 −0
Original line number Diff line number Diff line
@@ -302,6 +302,8 @@ static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *
{
	// 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(reg > 0x3f))
		return;
+7 −0
Original line number Diff line number Diff line
@@ -149,6 +149,13 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
				outl(0, emu->port + INTE2);
			status &= ~IPR_P16V;
		}
		if (status & IPR_A_GPIO) {
			if (emu->gpio_interrupt)
				emu->gpio_interrupt(emu);
			else
				snd_emu10k1_intr_disable(emu, INTE_A_GPIOENABLE);
			status &= ~IPR_A_GPIO;
		}

		if (status) {
			dev_err(emu->card->dev,