Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09668b44 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] emu10k1 - Add PM support



Modules: EMU10K1/EMU10K2 driver

Add PM support to emu10k1 driver.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent fe8be107
Loading
Loading
Loading
Loading
+29 −2
Original line number Original line Diff line number Diff line
@@ -1071,7 +1071,8 @@ struct snd_emu10k1 {


	unsigned long port;			/* I/O port number */
	unsigned long port;			/* I/O port number */
	unsigned int tos_link: 1,		/* tos link detected */
	unsigned int tos_link: 1,		/* tos link detected */
	    rear_ac97: 1;			/* rear channels are on AC'97 */
		rear_ac97: 1,			/* rear channels are on AC'97 */
		enable_ir: 1;
	/* Contains profile of card capabilities */
	/* Contains profile of card capabilities */
	const struct snd_emu_chip_details *card_capabilities;
	const struct snd_emu_chip_details *card_capabilities;
	unsigned int audigy;			/* is Audigy? */
	unsigned int audigy;			/* is Audigy? */
@@ -1108,6 +1109,7 @@ struct snd_emu10k1 {
	struct snd_pcm *pcm;
	struct snd_pcm *pcm;
	struct snd_pcm *pcm_mic;
	struct snd_pcm *pcm_mic;
	struct snd_pcm *pcm_efx;
	struct snd_pcm *pcm_efx;
	struct snd_pcm *pcm_multi;
	struct snd_pcm *pcm_p16v;
	struct snd_pcm *pcm_p16v;


	spinlock_t synth_lock;
	spinlock_t synth_lock;
@@ -1153,6 +1155,17 @@ struct snd_emu10k1 {


	unsigned int efx_voices_mask[2];
	unsigned int efx_voices_mask[2];
	unsigned int next_free_voice;
	unsigned int next_free_voice;

#ifdef CONFIG_PM
	unsigned int *saved_ptr;
	unsigned int *saved_gpr;
	unsigned int *tram_val_saved;
	unsigned int *tram_addr_saved;
	unsigned int *saved_icode;
	unsigned int *p16v_saved;
	unsigned int saved_a_iocfg, saved_hcfg;
#endif

};
};


int snd_emu10k1_create(struct snd_card *card,
int snd_emu10k1_create(struct snd_card *card,
@@ -1178,11 +1191,11 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep


irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs);


/* initialization */
void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int voice);
void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int voice);
int snd_emu10k1_init_efx(struct snd_emu10k1 *emu);
int snd_emu10k1_init_efx(struct snd_emu10k1 *emu);
void snd_emu10k1_free_efx(struct snd_emu10k1 *emu);
void snd_emu10k1_free_efx(struct snd_emu10k1 *emu);
int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size);
int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size);
int snd_emu10k1_done(struct snd_emu10k1 * emu);


/* I/O functions */
/* I/O functions */
unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
@@ -1206,6 +1219,20 @@ unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);
void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);
unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);
unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);


#ifdef CONFIG_PM
void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu);
void snd_emu10k1_resume_init(struct snd_emu10k1 *emu);
void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu);
int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu);
void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu);
void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu);
void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu);
int snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu);
void snd_p16v_free_pm_buffer(struct snd_emu10k1 *emu);
void snd_p16v_suspend(struct snd_emu10k1 *emu);
void snd_p16v_resume(struct snd_emu10k1 *emu);
#endif

/* memory allocation */
/* memory allocation */
struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream);
struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream);
int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
+91 −53
Original line number Original line Diff line number Diff line
@@ -125,65 +125,43 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
	if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev],
	if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev],
				      (long)max_buffer_size[dev] * 1024 * 1024,
				      (long)max_buffer_size[dev] * 1024 * 1024,
				      enable_ir[dev], subsystem[dev],
				      enable_ir[dev], subsystem[dev],
				      &emu)) < 0) {
				      &emu)) < 0)
		snd_card_free(card);
		goto error;
		return err;
	card->private_data = emu;
	}		
	if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
	if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) {
		goto error;
		snd_card_free(card);
	if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
		return err;
		goto error;
	}		
	if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0)
	if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) {
		goto error;
		snd_card_free(card);
		return err;
	}		
	if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) {
		snd_card_free(card);
		return err;
	}
	/* This stores the periods table. */
	/* This stores the periods table. */
	if (emu->card_capabilities->ca0151_chip) { /* P16V */	
	if (emu->card_capabilities->ca0151_chip) { /* P16V */	
		if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &emu->p16v_buffer) < 0) {
		if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
			snd_p16v_free(emu);
					       1024, &emu->p16v_buffer)) < 0)
			return -ENOMEM;
			goto error;
		}
	}
	}


	if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) {
	if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0)
		snd_card_free(card);
		goto error;
		return err;
	}
	
	
	if ((err = snd_emu10k1_timer(emu, 0)) < 0) {
	if ((err = snd_emu10k1_timer(emu, 0)) < 0)
		snd_card_free(card);
		goto error;
		return err;
	}


	if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) {
	if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0)
		snd_card_free(card);
		goto error;
		return err;
	}
	if (emu->card_capabilities->ca0151_chip) { /* P16V */
	if (emu->card_capabilities->ca0151_chip) { /* P16V */
		if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) {
		if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0)
			snd_card_free(card);
			goto error;
			return err;
		}
	}
	}
	if (emu->audigy) {
	if (emu->audigy) {
		if ((err = snd_emu10k1_audigy_midi(emu)) < 0) {
		if ((err = snd_emu10k1_audigy_midi(emu)) < 0)
			snd_card_free(card);
			goto error;
			return err;
		}
	} else {
	} else {
		if ((err = snd_emu10k1_midi(emu)) < 0) {
		if ((err = snd_emu10k1_midi(emu)) < 0)
			snd_card_free(card);
			goto error;
			return err;
		}
	}
	if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0) {
		snd_card_free(card);
		return err;
	}
	}
	if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0)
		goto error;
#ifdef ENABLE_SYNTH
#ifdef ENABLE_SYNTH
	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
			       sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 ||
			       sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 ||
@@ -206,13 +184,16 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
		 "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
		 "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
		 card->shortname, emu->revision, emu->serial, emu->port, emu->irq);
		 card->shortname, emu->revision, emu->serial, emu->port, emu->irq);


	if ((err = snd_card_register(card)) < 0) {
	if ((err = snd_card_register(card)) < 0)
		snd_card_free(card);
		goto error;
		return err;

	}
	pci_set_drvdata(pci, card);
	pci_set_drvdata(pci, card);
	dev++;
	dev++;
	return 0;
	return 0;

 error:
	snd_card_free(card);
	return err;
}
}


static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
@@ -221,11 +202,68 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
	pci_set_drvdata(pci, NULL);
	pci_set_drvdata(pci, NULL);
}
}



#ifdef CONFIG_PM
static int snd_emu10k1_suspend(struct pci_dev *pci, pm_message_t state)
{
	struct snd_card *card = pci_get_drvdata(pci);
	struct snd_emu10k1 *emu = card->private_data;

	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);

	snd_pcm_suspend_all(emu->pcm);
	snd_pcm_suspend_all(emu->pcm_mic);
	snd_pcm_suspend_all(emu->pcm_efx);
	snd_pcm_suspend_all(emu->pcm_multi);
	snd_pcm_suspend_all(emu->pcm_p16v);

	snd_ac97_suspend(emu->ac97);

	snd_emu10k1_efx_suspend(emu);
	snd_emu10k1_suspend_regs(emu);
	if (emu->card_capabilities->ca0151_chip)
		snd_p16v_suspend(emu);

	snd_emu10k1_done(emu);

	pci_set_power_state(pci, PCI_D3hot);
	pci_disable_device(pci);
	pci_save_state(pci);
	return 0;
}

int snd_emu10k1_resume(struct pci_dev *pci)
{
	struct snd_card *card = pci_get_drvdata(pci);
	struct snd_emu10k1 *emu = card->private_data;

	pci_restore_state(pci);
	pci_enable_device(pci);
	pci_set_power_state(pci, PCI_D0);
	pci_set_master(pci);
	
	snd_emu10k1_resume_init(emu);
	snd_emu10k1_efx_resume(emu);
	snd_ac97_resume(emu->ac97);
	snd_emu10k1_resume_regs(emu);

	if (emu->card_capabilities->ca0151_chip)
		snd_p16v_resume(emu);

	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
	return 0;
}
#endif

static struct pci_driver driver = {
static struct pci_driver driver = {
	.name = "EMU10K1_Audigy",
	.name = "EMU10K1_Audigy",
	.id_table = snd_emu10k1_ids,
	.id_table = snd_emu10k1_ids,
	.probe = snd_card_emu10k1_probe,
	.probe = snd_card_emu10k1_probe,
	.remove = __devexit_p(snd_card_emu10k1_remove),
	.remove = __devexit_p(snd_card_emu10k1_remove),
#ifdef CONFIG_PM
	.suspend = snd_emu10k1_suspend,
	.resume = snd_emu10k1_resume,
#endif
};
};


static int __init alsa_card_emu10k1_init(void)
static int __init alsa_card_emu10k1_init(void)
+202 −106
Original line number Original line Diff line number Diff line
@@ -42,12 +42,6 @@
#include "p16v.h"
#include "p16v.h"
#include "tina2.h"
#include "tina2.h"


#if 0
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Creative Labs, Inc.");
MODULE_DESCRIPTION("Routines for control of EMU10K1 chips");
MODULE_LICENSE("GPL");
#endif

/*************************************************************************
/*************************************************************************
 * EMU10K1 init / done
 * EMU10K1 init / done
 *************************************************************************/
 *************************************************************************/
@@ -97,17 +91,14 @@ void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch)
	}
	}
}
}


static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir)
static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
{
{
	int ch, idx, err;
	unsigned int silent_page;
	unsigned int silent_page;

	int ch;
	emu->fx8010.itram_size = (16 * 1024)/2;
	emu->fx8010.etram_pages.area = NULL;
	emu->fx8010.etram_pages.bytes = 0;


	/* disable audio and lock cache */
	/* disable audio and lock cache */
	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
	     emu->port + HCFG);


	/* reset recording buffers */
	/* reset recording buffers */
	snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE);
	snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE);
@@ -128,48 +119,17 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir)
		/* set SPDIF bypass mode */
		/* set SPDIF bypass mode */
		snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT);
		snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT);
		/* enable rear left + rear right AC97 slots */
		/* enable rear left + rear right AC97 slots */
		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT | AC97SLOT_REAR_LEFT);
		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT |
				      AC97SLOT_REAR_LEFT);
	}
	}


	/* init envelope engine */
	/* init envelope engine */
	for (ch = 0; ch < NUM_G; ch++) {
	for (ch = 0; ch < NUM_G; ch++)
		emu->voices[ch].emu = emu;
		emu->voices[ch].number = ch;
		snd_emu10k1_voice_init(emu, ch);
		snd_emu10k1_voice_init(emu, ch);
	}


	/*
	snd_emu10k1_ptr_write(emu, SPCS0, 0, emu->spdif_bits[0]);
	 *  Init to 0x02109204 :
	snd_emu10k1_ptr_write(emu, SPCS1, 0, emu->spdif_bits[1]);
	 *  Clock accuracy    = 0     (1000ppm)
	snd_emu10k1_ptr_write(emu, SPCS2, 0, emu->spdif_bits[2]);
	 *  Sample Rate       = 2     (48kHz)
	 *  Audio Channel     = 1     (Left of 2)
	 *  Source Number     = 0     (Unspecified)
	 *  Generation Status = 1     (Original for Cat Code 12)
	 *  Cat Code          = 12    (Digital Signal Mixer)
	 *  Mode              = 0     (Mode 0)
	 *  Emphasis          = 0     (None)
	 *  CP                = 1     (Copyright unasserted)
	 *  AN                = 0     (Audio data)
	 *  P                 = 0     (Consumer)
	 */
	snd_emu10k1_ptr_write(emu, SPCS0, 0,
			emu->spdif_bits[0] =
			SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
			SPCS_GENERATIONSTATUS | 0x00001200 |
			0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
	snd_emu10k1_ptr_write(emu, SPCS1, 0,
			emu->spdif_bits[1] =
			SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
			SPCS_GENERATIONSTATUS | 0x00001200 |
			0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
	snd_emu10k1_ptr_write(emu, SPCS2, 0,
			emu->spdif_bits[2] =
			SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
			SPCS_GENERATIONSTATUS | 0x00001200 |
			0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);


	if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
	if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
		/* Hacks for Alice3 to work independent of haP16V driver */
		/* Hacks for Alice3 to work independent of haP16V driver */
@@ -196,7 +156,7 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir)
		/* Hacks for Alice3 to work independent of haP16V driver */
		/* Hacks for Alice3 to work independent of haP16V driver */
		u32 tmp;
		u32 tmp;


		snd_printk(KERN_ERR "Audigy2 value:Special config.\n");
		snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
		//Setup SRCMulti_I2S SamplingRate
		//Setup SRCMulti_I2S SamplingRate
		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
		tmp &= 0xfffff1ff;
		tmp &= 0xfffff1ff;
@@ -221,14 +181,6 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir)
		outl(tmp, emu->port + A_IOCFG);
		outl(tmp, emu->port + A_IOCFG);
	}
	}



	/*
	 *  Clear page with silence & setup all pointers to this page
	 */
	memset(emu->silent_page.area, 0, PAGE_SIZE);
	silent_page = emu->silent_page.addr << 1;
	for (idx = 0; idx < MAXPAGES; idx++)
		((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);
	snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
	snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
	snd_emu10k1_ptr_write(emu, TCB, 0, 0);	/* taken from original driver */
	snd_emu10k1_ptr_write(emu, TCB, 0, 0);	/* taken from original driver */
	snd_emu10k1_ptr_write(emu, TCBS, 0, 4);	/* taken from original driver */
	snd_emu10k1_ptr_write(emu, TCBS, 0, 4);	/* taken from original driver */
@@ -287,12 +239,11 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir)
		outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
		outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
	}
	}


	/*
	return 0;
	 *  Initialize the effect engine
}
	 */
	if ((err = snd_emu10k1_init_efx(emu)) < 0)
		return err;


static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
{
	/*
	/*
	 *  Enable the audio bit
	 *  Enable the audio bit
	 */
	 */
@@ -335,15 +286,9 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir)
#endif
#endif


	snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
	snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);

	emu->reserved_page = (struct snd_emu10k1_memblk *)snd_emu10k1_synth_alloc(emu, 4096);
	if (emu->reserved_page)
		emu->reserved_page->map_locked = 1;
	
	return 0;
}
}


static int snd_emu10k1_done(struct snd_emu10k1 * emu)
int snd_emu10k1_done(struct snd_emu10k1 * emu)
{
{
	int ch;
	int ch;


@@ -382,18 +327,10 @@ static int snd_emu10k1_done(struct snd_emu10k1 * emu)
	snd_emu10k1_ptr_write(emu, SOLEL, 0, 0);
	snd_emu10k1_ptr_write(emu, SOLEL, 0, 0);
	snd_emu10k1_ptr_write(emu, SOLEH, 0, 0);
	snd_emu10k1_ptr_write(emu, SOLEH, 0, 0);


	/* remove reserved page */
	if (emu->reserved_page != NULL) {
		snd_emu10k1_synth_free(emu, (struct snd_util_memblk *)emu->reserved_page);
		emu->reserved_page = NULL;
	}

	/* disable audio and lock cache */
	/* disable audio and lock cache */
	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
	snd_emu10k1_ptr_write(emu, PTB, 0, 0);
	snd_emu10k1_ptr_write(emu, PTB, 0, 0);


	snd_emu10k1_free_efx(emu);

	return 0;
	return 0;
}
}


@@ -609,11 +546,22 @@ static int __devinit snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
 *  Create the EMU10K1 instance
 *  Create the EMU10K1 instance
 */
 */


#ifdef CONFIG_PM
static int alloc_pm_buffer(struct snd_emu10k1 *emu);
static void free_pm_buffer(struct snd_emu10k1 *emu);
#endif

static int snd_emu10k1_free(struct snd_emu10k1 *emu)
static int snd_emu10k1_free(struct snd_emu10k1 *emu)
{
{
	if (emu->port) {	/* avoid access to already used hardware */
	if (emu->port) {	/* avoid access to already used hardware */
	       	snd_emu10k1_fx8010_tram_setup(emu, 0);
	       	snd_emu10k1_fx8010_tram_setup(emu, 0);
		snd_emu10k1_done(emu);
		snd_emu10k1_done(emu);
		/* remove reserved page */
		if (emu->reserved_page) {
			snd_emu10k1_synth_free(emu, (struct snd_util_memblk *)emu->reserved_page);
			emu->reserved_page = NULL;
		}
		snd_emu10k1_free_efx(emu);
       	}
       	}
	if (emu->memhdr)
	if (emu->memhdr)
		snd_util_memhdr_free(emu->memhdr);
		snd_util_memhdr_free(emu->memhdr);
@@ -623,13 +571,16 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
		snd_dma_free_pages(&emu->ptb_pages);
		snd_dma_free_pages(&emu->ptb_pages);
	vfree(emu->page_ptr_table);
	vfree(emu->page_ptr_table);
	vfree(emu->page_addr_table);
	vfree(emu->page_addr_table);
#ifdef CONFIG_PM
	free_pm_buffer(emu);
#endif
	if (emu->irq >= 0)
	if (emu->irq >= 0)
		free_irq(emu->irq, (void *)emu);
		free_irq(emu->irq, (void *)emu);
	if (emu->port)
	if (emu->port)
		pci_release_regions(emu->pci);
		pci_release_regions(emu->pci);
	pci_disable_device(emu->pci);
	if (emu->card_capabilities->ca0151_chip) /* P16V */	
	if (emu->card_capabilities->ca0151_chip) /* P16V */	
		snd_p16v_free(emu);
		snd_p16v_free(emu);
	pci_disable_device(emu->pci);
	kfree(emu);
	kfree(emu);
	return 0;
	return 0;
}
}
@@ -900,9 +851,10 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
		       struct snd_emu10k1 ** remu)
		       struct snd_emu10k1 ** remu)
{
{
	struct snd_emu10k1 *emu;
	struct snd_emu10k1 *emu;
	int err;
	int idx, err;
	int is_audigy;
	int is_audigy;
	unsigned char revision;
	unsigned char revision;
	unsigned int silent_page;
	const struct snd_emu_chip_details *c;
	const struct snd_emu_chip_details *c;
	static struct snd_device_ops ops = {
	static struct snd_device_ops ops = {
		.dev_free =	snd_emu10k1_dev_free,
		.dev_free =	snd_emu10k1_dev_free,
@@ -1012,34 +964,34 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
	emu->port = pci_resource_start(pci, 0);
	emu->port = pci_resource_start(pci, 0);


	if (request_irq(pci->irq, snd_emu10k1_interrupt, SA_INTERRUPT|SA_SHIRQ, "EMU10K1", (void *)emu)) {
	if (request_irq(pci->irq, snd_emu10k1_interrupt, SA_INTERRUPT|SA_SHIRQ, "EMU10K1", (void *)emu)) {
		snd_emu10k1_free(emu);
		err = -EBUSY;
		return -EBUSY;
		goto error;
	}
	}
	emu->irq = pci->irq;
	emu->irq = pci->irq;


	emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
	emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
				32 * 1024, &emu->ptb_pages) < 0) {
				32 * 1024, &emu->ptb_pages) < 0) {
		snd_emu10k1_free(emu);
		err = -ENOMEM;
		return -ENOMEM;
		goto error;
	}
	}


	emu->page_ptr_table = (void **)vmalloc(emu->max_cache_pages * sizeof(void*));
	emu->page_ptr_table = (void **)vmalloc(emu->max_cache_pages * sizeof(void*));
	emu->page_addr_table = (unsigned long*)vmalloc(emu->max_cache_pages * sizeof(unsigned long));
	emu->page_addr_table = (unsigned long*)vmalloc(emu->max_cache_pages * sizeof(unsigned long));
	if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) {
	if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) {
		snd_emu10k1_free(emu);
		err = -ENOMEM;
		return -ENOMEM;
		goto error;
	}
	}


	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
				EMUPAGESIZE, &emu->silent_page) < 0) {
				EMUPAGESIZE, &emu->silent_page) < 0) {
		snd_emu10k1_free(emu);
		err = -ENOMEM;
		return -ENOMEM;
		goto error;
	}
	}
	emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE);
	emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE);
	if (emu->memhdr == NULL) {
	if (emu->memhdr == NULL) {
		snd_emu10k1_free(emu);
		err = -ENOMEM;
		return -ENOMEM;
		goto error;
	}
	}
	emu->memhdr->block_extra_size = sizeof(struct snd_emu10k1_memblk) -
	emu->memhdr->block_extra_size = sizeof(struct snd_emu10k1_memblk) -
		sizeof(struct snd_util_memblk);
		sizeof(struct snd_util_memblk);
@@ -1053,40 +1005,184 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
		extout_mask = 0x7fff;
		extout_mask = 0x7fff;
	emu->fx8010.extin_mask = extin_mask;
	emu->fx8010.extin_mask = extin_mask;
	emu->fx8010.extout_mask = extout_mask;
	emu->fx8010.extout_mask = extout_mask;
	emu->enable_ir = enable_ir;


	if (emu->card_capabilities->ecard) {
	if (emu->card_capabilities->ecard) {
		if ((err = snd_emu10k1_ecard_init(emu)) < 0) {
		if ((err = snd_emu10k1_ecard_init(emu)) < 0)
			snd_emu10k1_free(emu);
			goto error;
			return err;
		}
	} else if (emu->card_capabilities->ca_cardbus_chip) {
	} else if (emu->card_capabilities->ca_cardbus_chip) {
		if ((err = snd_emu10k1_cardbus_init(emu)) < 0) {
		if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
			snd_emu10k1_free(emu);
			goto error;
			return err;
		}
	} else {
	} else {
		/* 5.1: Enable the additional AC97 Slots. If the emu10k1 version
		/* 5.1: Enable the additional AC97 Slots. If the emu10k1 version
			does not support this, it shouldn't do any harm */
			does not support this, it shouldn't do any harm */
		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
	}
	}


	if ((err = snd_emu10k1_init(emu, enable_ir)) < 0) {
	/* initialize TRAM setup */
		snd_emu10k1_free(emu);
	emu->fx8010.itram_size = (16 * 1024)/2;
		return err;
	emu->fx8010.etram_pages.area = NULL;
	}
	emu->fx8010.etram_pages.bytes = 0;


	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0) {
	/*
		snd_emu10k1_free(emu);
	 *  Init to 0x02109204 :
		return err;
	 *  Clock accuracy    = 0     (1000ppm)
	 *  Sample Rate       = 2     (48kHz)
	 *  Audio Channel     = 1     (Left of 2)
	 *  Source Number     = 0     (Unspecified)
	 *  Generation Status = 1     (Original for Cat Code 12)
	 *  Cat Code          = 12    (Digital Signal Mixer)
	 *  Mode              = 0     (Mode 0)
	 *  Emphasis          = 0     (None)
	 *  CP                = 1     (Copyright unasserted)
	 *  AN                = 0     (Audio data)
	 *  P                 = 0     (Consumer)
	 */
	emu->spdif_bits[0] = emu->spdif_bits[1] =
		emu->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
		SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
		SPCS_GENERATIONSTATUS | 0x00001200 |
		0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;

	emu->reserved_page = (struct snd_emu10k1_memblk *)
		snd_emu10k1_synth_alloc(emu, 4096);
	if (emu->reserved_page)
		emu->reserved_page->map_locked = 1;
	
	/* Clear silent pages and set up pointers */
	memset(emu->silent_page.area, 0, PAGE_SIZE);
	silent_page = emu->silent_page.addr << 1;
	for (idx = 0; idx < MAXPAGES; idx++)
		((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);

	/* set up voice indices */
	for (idx = 0; idx < NUM_G; idx++) {
		emu->voices[idx].emu = emu;
		emu->voices[idx].number = idx;
	}
	}


	if ((err = snd_emu10k1_init(emu, enable_ir, 0)) < 0)
		goto error;
#ifdef CONFIG_PM
	if ((err = alloc_pm_buffer(emu)) < 0)
		goto error;
#endif

	/*  Initialize the effect engine */
	if ((err = snd_emu10k1_init_efx(emu)) < 0)
		goto error;
	snd_emu10k1_audio_enable(emu);

	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0)
		goto error;

	snd_emu10k1_proc_init(emu);
	snd_emu10k1_proc_init(emu);


	snd_card_set_dev(card, &pci->dev);
	snd_card_set_dev(card, &pci->dev);
	*remu = emu;
	*remu = emu;
	return 0;
	return 0;

 error:
	snd_emu10k1_free(emu);
	return err;
}

#ifdef CONFIG_PM
static unsigned char saved_regs[] = {
	CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP,
	FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL,
	ATKHLDM, DCYSUSM, LFOVAL2, IP, IFATN, PEFE, FMMOD, TREMFRQ, FM2FRQ2,
	TEMPENV, ADCCR, FXWC, MICBA, ADCBA, FXBA,
	MICBS, ADCBS, FXBS, CDCS, GPSCS, SPCS0, SPCS1, SPCS2,
	SPBYPASS, AC97SLOT, CDSRCS, GPSRCS, ZVSRCS, MICIDX, ADCIDX, FXIDX,
	0xff /* end */
};
static unsigned char saved_regs_audigy[] = {
	A_ADCIDX, A_MICIDX, A_FXWC1, A_FXWC2, A_SAMPLE_RATE,
	A_FXRT2, A_SENDAMOUNTS, A_FXRT1,
	0xff /* end */
};

static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu)
{
	int size;

	size = ARRAY_SIZE(saved_regs);
	if (emu->audigy)
		size += ARRAY_SIZE(saved_regs_audigy);
	emu->saved_ptr = vmalloc(4 * NUM_G * size);
	if (! emu->saved_ptr)
		return -ENOMEM;
	if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0)
		return -ENOMEM;
	if (emu->card_capabilities->ca0151_chip &&
	    snd_p16v_alloc_pm_buffer(emu) < 0)
		return -ENOMEM;
	return 0;
}

static void free_pm_buffer(struct snd_emu10k1 *emu)
{
	vfree(emu->saved_ptr);
	snd_emu10k1_efx_free_pm_buffer(emu);
	if (emu->card_capabilities->ca0151_chip)
		snd_p16v_free_pm_buffer(emu);
}

void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu)
{
	int i;
	unsigned char *reg;
	unsigned int *val;

	val = emu->saved_ptr;
	for (reg = saved_regs; *reg != 0xff; reg++)
		for (i = 0; i < NUM_G; i++, val++)
			*val = snd_emu10k1_ptr_read(emu, *reg, i);
	if (emu->audigy) {
		for (reg = saved_regs_audigy; *reg != 0xff; reg++)
			for (i = 0; i < NUM_G; i++, val++)
				*val = snd_emu10k1_ptr_read(emu, *reg, i);
	}
	if (emu->audigy)
		emu->saved_a_iocfg = inl(emu->port + A_IOCFG);
	emu->saved_hcfg = inl(emu->port + HCFG);
}

void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
{
	if (emu->card_capabilities->ecard)
		snd_emu10k1_ecard_init(emu);
	else
		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
	snd_emu10k1_init(emu, emu->enable_ir, 1);
}
}


void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu)
{
	int i;
	unsigned char *reg;
	unsigned int *val;

	snd_emu10k1_audio_enable(emu);

	/* resore for spdif */
	if (emu->audigy)
		outl(emu->port + A_IOCFG, emu->saved_a_iocfg);
	outl(emu->port + HCFG, emu->saved_hcfg);

	val = emu->saved_ptr;
	for (reg = saved_regs; *reg != 0xff; reg++)
		for (i = 0; i < NUM_G; i++, val++)
			snd_emu10k1_ptr_write(emu, *reg, i, *val);
	if (emu->audigy) {
		for (reg = saved_regs_audigy; *reg != 0xff; reg++)
			for (i = 0; i < NUM_G; i++, val++)
				snd_emu10k1_ptr_write(emu, *reg, i, *val);
	}
}
#endif

/* memory.c */
/* memory.c */
EXPORT_SYMBOL(snd_emu10k1_synth_alloc);
EXPORT_SYMBOL(snd_emu10k1_synth_alloc);
EXPORT_SYMBOL(snd_emu10k1_synth_free);
EXPORT_SYMBOL(snd_emu10k1_synth_free);
+114 −7
Original line number Original line Diff line number Diff line
@@ -1071,9 +1071,6 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
	u32 *gpr_map;
	u32 *gpr_map;
	mm_segment_t seg;
	mm_segment_t seg;


	spin_lock_init(&emu->fx8010.irq_lock);
	INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);

	if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
	if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
	    (icode->gpr_map = (u_int32_t __user *)
	    (icode->gpr_map = (u_int32_t __user *)
	     kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
	     kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
@@ -1541,9 +1538,6 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
	u32 *gpr_map;
	u32 *gpr_map;
	mm_segment_t seg;
	mm_segment_t seg;


	spin_lock_init(&emu->fx8010.irq_lock);
	INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);

	if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
	if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
		return -ENOMEM;
		return -ENOMEM;
	if ((icode->gpr_map = (u_int32_t __user *)
	if ((icode->gpr_map = (u_int32_t __user *)
@@ -2102,6 +2096,8 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)


int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
{
{
	spin_lock_init(&emu->fx8010.irq_lock);
	INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
	if (emu->audigy)
	if (emu->audigy)
		return _snd_emu10k1_audigy_init_efx(emu);
		return _snd_emu10k1_audigy_init_efx(emu);
	else
	else
@@ -2387,3 +2383,114 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct
		*rhwdep = hw;
		*rhwdep = hw;
	return 0;
	return 0;
}
}

#ifdef CONFIG_PM
int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
{
	int len;

	len = emu->audigy ? 0x200 : 0x100;
	emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
	if (! emu->saved_gpr)
		return -ENOMEM;
	len = emu->audigy ? 0x100 : 0xa0;
	emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
	emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
	if (! emu->tram_val_saved || ! emu->tram_addr_saved)
		return -ENOMEM;
	len = emu->audigy ? 2 * 1024 : 2 * 512;
	emu->saved_icode = vmalloc(len * 4);
	if (! emu->saved_icode)
		return -ENOMEM;
	return 0;
}

void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
{
	kfree(emu->saved_gpr);
	kfree(emu->tram_val_saved);
	kfree(emu->tram_addr_saved);
	vfree(emu->saved_icode);
}

/*
 * save/restore GPR, TRAM and codes
 */
void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
{
	int i, len;

	len = emu->audigy ? 0x200 : 0x100;
	for (i = 0; i < len; i++)
		emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);

	len = emu->audigy ? 0x100 : 0xa0;
	for (i = 0; i < len; i++) {
		emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
		emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
		if (emu->audigy) {
			emu->tram_addr_saved[i] >>= 12;
			emu->tram_addr_saved[i] |=
				snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
		}
	}

	len = emu->audigy ? 2 * 1024 : 2 * 512;
	for (i = 0; i < len; i++)
		emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
}

void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
{
	int i, len;

	/* set up TRAM */
	if (emu->fx8010.etram_pages.bytes > 0) {
		unsigned size, size_reg = 0;
		size = emu->fx8010.etram_pages.bytes / 2;
		size = (size - 1) >> 13;
		while (size) {
			size >>= 1;
			size_reg++;
		}
		outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
		snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
		snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
		outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
	}

	if (emu->audigy)
		snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
	else
		snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);

	len = emu->audigy ? 0x200 : 0x100;
	for (i = 0; i < len; i++)
		snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);

	len = emu->audigy ? 0x100 : 0xa0;
	for (i = 0; i < len; i++) {
		snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
				      emu->tram_val_saved[i]);
		if (! emu->audigy)
			snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
					      emu->tram_addr_saved[i]);
		else {
			snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
					      emu->tram_addr_saved[i] << 12);
			snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
					      emu->tram_addr_saved[i] >> 20);
		}
	}

	len = emu->audigy ? 2 * 1024 : 2 * 512;
	for (i = 0; i < len; i++)
		snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);

	/* start FX processor when the DSP code is updated */
	if (emu->audigy)
		snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
	else
		snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
}
#endif
+13 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading