xref: /linux/sound/pci/emu10k1/emupcm.c (revision 7195fb46dafb8750ed4055804cb131f376eb854e)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
41da177e4SLinus Torvalds  *                   Creative Labs, Inc.
51da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / PCM routines
61da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *  BUGS:
91da177e4SLinus Torvalds  *    --
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *  TODO:
121da177e4SLinus Torvalds  *    --
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/pci.h>
161da177e4SLinus Torvalds #include <linux/delay.h>
171da177e4SLinus Torvalds #include <linux/slab.h>
181da177e4SLinus Torvalds #include <linux/time.h>
191da177e4SLinus Torvalds #include <linux/init.h>
201da177e4SLinus Torvalds #include <sound/core.h>
211da177e4SLinus Torvalds #include <sound/emu10k1.h>
221da177e4SLinus Torvalds 
23eb4698f3STakashi Iwai static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu,
24eb4698f3STakashi Iwai 				      struct snd_emu10k1_voice *voice)
251da177e4SLinus Torvalds {
26eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
271da177e4SLinus Torvalds 
2812bda107STakashi Iwai 	epcm = voice->epcm;
2912bda107STakashi Iwai 	if (!epcm)
301da177e4SLinus Torvalds 		return;
311da177e4SLinus Torvalds 	if (epcm->substream == NULL)
321da177e4SLinus Torvalds 		return;
331da177e4SLinus Torvalds #if 0
346f002b02STakashi Iwai 	dev_dbg(emu->card->dev,
356f002b02STakashi Iwai 		"IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
361da177e4SLinus Torvalds 			epcm->substream->runtime->hw->pointer(emu, epcm->substream),
371da177e4SLinus Torvalds 			snd_pcm_lib_period_bytes(epcm->substream),
381da177e4SLinus Torvalds 			snd_pcm_lib_buffer_bytes(epcm->substream));
391da177e4SLinus Torvalds #endif
401da177e4SLinus Torvalds 	snd_pcm_period_elapsed(epcm->substream);
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds 
43eb4698f3STakashi Iwai static void snd_emu10k1_pcm_ac97adc_interrupt(struct snd_emu10k1 *emu,
44eb4698f3STakashi Iwai 					      unsigned int status)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds #if 0
471da177e4SLinus Torvalds 	if (status & IPR_ADCBUFHALFFULL) {
481da177e4SLinus Torvalds 		if (emu->pcm_capture_substream->runtime->mode == SNDRV_PCM_MODE_FRAME)
491da177e4SLinus Torvalds 			return;
501da177e4SLinus Torvalds 	}
511da177e4SLinus Torvalds #endif
521da177e4SLinus Torvalds 	snd_pcm_period_elapsed(emu->pcm_capture_substream);
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds 
55eb4698f3STakashi Iwai static void snd_emu10k1_pcm_ac97mic_interrupt(struct snd_emu10k1 *emu,
56eb4698f3STakashi Iwai 					      unsigned int status)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds #if 0
591da177e4SLinus Torvalds 	if (status & IPR_MICBUFHALFFULL) {
601da177e4SLinus Torvalds 		if (emu->pcm_capture_mic_substream->runtime->mode == SNDRV_PCM_MODE_FRAME)
611da177e4SLinus Torvalds 			return;
621da177e4SLinus Torvalds 	}
631da177e4SLinus Torvalds #endif
641da177e4SLinus Torvalds 	snd_pcm_period_elapsed(emu->pcm_capture_mic_substream);
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
67eb4698f3STakashi Iwai static void snd_emu10k1_pcm_efx_interrupt(struct snd_emu10k1 *emu,
68eb4698f3STakashi Iwai 					  unsigned int status)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds #if 0
711da177e4SLinus Torvalds 	if (status & IPR_EFXBUFHALFFULL) {
721da177e4SLinus Torvalds 		if (emu->pcm_capture_efx_substream->runtime->mode == SNDRV_PCM_MODE_FRAME)
731da177e4SLinus Torvalds 			return;
741da177e4SLinus Torvalds 	}
751da177e4SLinus Torvalds #endif
761da177e4SLinus Torvalds 	snd_pcm_period_elapsed(emu->pcm_capture_efx_substream);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
79bdb3b567SOswald Buddenhagen static void snd_emu10k1_pcm_free_voices(struct snd_emu10k1_pcm *epcm)
801da177e4SLinus Torvalds {
81bdb3b567SOswald Buddenhagen 	for (unsigned i = 0; i < ARRAY_SIZE(epcm->voices); i++) {
821da177e4SLinus Torvalds 		if (epcm->voices[i]) {
831da177e4SLinus Torvalds 			snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
841da177e4SLinus Torvalds 			epcm->voices[i] = NULL;
851da177e4SLinus Torvalds 		}
861da177e4SLinus Torvalds 	}
87bdb3b567SOswald Buddenhagen }
88bdb3b567SOswald Buddenhagen 
89a915d604SOswald Buddenhagen static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm *epcm,
90a915d604SOswald Buddenhagen 					 int type, int count, int channels)
91bdb3b567SOswald Buddenhagen {
92a915d604SOswald Buddenhagen 	int err;
93bdb3b567SOswald Buddenhagen 
94bdb3b567SOswald Buddenhagen 	snd_emu10k1_pcm_free_voices(epcm);
95bdb3b567SOswald Buddenhagen 
961da177e4SLinus Torvalds 	err = snd_emu10k1_voice_alloc(epcm->emu,
97a915d604SOswald Buddenhagen 				      type, count, channels,
98b4fea2d3SOswald Buddenhagen 				      epcm, &epcm->voices[0]);
991da177e4SLinus Torvalds 	if (err < 0)
1001da177e4SLinus Torvalds 		return err;
101a915d604SOswald Buddenhagen 
1021da177e4SLinus Torvalds 	if (epcm->extra == NULL) {
1035b1cd21fSOswald Buddenhagen 		// The hardware supports only (half-)loop interrupts, so to support an
1045b1cd21fSOswald Buddenhagen 		// arbitrary number of periods per buffer, we use an extra voice with a
1055b1cd21fSOswald Buddenhagen 		// period-sized loop as the interrupt source. Additionally, the interrupt
1065b1cd21fSOswald Buddenhagen 		// timing of the hardware is "suboptimal" and needs some compensation.
1071da177e4SLinus Torvalds 		err = snd_emu10k1_voice_alloc(epcm->emu,
108a915d604SOswald Buddenhagen 					      type + 1, 1, 1,
109b4fea2d3SOswald Buddenhagen 					      epcm, &epcm->extra);
1101da177e4SLinus Torvalds 		if (err < 0) {
11128a97c19STakashi Iwai 			/*
1126f002b02STakashi Iwai 			dev_dbg(emu->card->dev, "pcm_channel_alloc: "
11328a97c19STakashi Iwai 			       "failed extra: voices=%d, frame=%d\n",
11428a97c19STakashi Iwai 			       voices, frame);
11528a97c19STakashi Iwai 			*/
116bdb3b567SOswald Buddenhagen 			snd_emu10k1_pcm_free_voices(epcm);
1171da177e4SLinus Torvalds 			return err;
1181da177e4SLinus Torvalds 		}
1191da177e4SLinus Torvalds 		epcm->extra->interrupt = snd_emu10k1_pcm_interrupt;
1201da177e4SLinus Torvalds 	}
121bdb3b567SOswald Buddenhagen 
1221da177e4SLinus Torvalds 	return 0;
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds 
125973f1d6cSTakashi Iwai static const unsigned int capture_period_sizes[31] = {
1261da177e4SLinus Torvalds 	384,	448,	512,	640,
1271da177e4SLinus Torvalds 	384*2,	448*2,	512*2,	640*2,
1281da177e4SLinus Torvalds 	384*4,	448*4,	512*4,	640*4,
1291da177e4SLinus Torvalds 	384*8,	448*8,	512*8,	640*8,
1301da177e4SLinus Torvalds 	384*16,	448*16,	512*16,	640*16,
1311da177e4SLinus Torvalds 	384*32,	448*32,	512*32,	640*32,
1321da177e4SLinus Torvalds 	384*64,	448*64,	512*64,	640*64,
1331da177e4SLinus Torvalds 	384*128,448*128,512*128
1341da177e4SLinus Torvalds };
1351da177e4SLinus Torvalds 
136973f1d6cSTakashi Iwai static const struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = {
1371da177e4SLinus Torvalds 	.count = 31,
1381da177e4SLinus Torvalds 	.list = capture_period_sizes,
1391da177e4SLinus Torvalds 	.mask = 0
1401da177e4SLinus Torvalds };
1411da177e4SLinus Torvalds 
142973f1d6cSTakashi Iwai static const unsigned int capture_rates[8] = {
1431da177e4SLinus Torvalds 	8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000
1441da177e4SLinus Torvalds };
1451da177e4SLinus Torvalds 
146973f1d6cSTakashi Iwai static const struct snd_pcm_hw_constraint_list hw_constraints_capture_rates = {
1471da177e4SLinus Torvalds 	.count = 8,
1481da177e4SLinus Torvalds 	.list = capture_rates,
1491da177e4SLinus Torvalds 	.mask = 0
1501da177e4SLinus Torvalds };
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds static unsigned int snd_emu10k1_capture_rate_reg(unsigned int rate)
1531da177e4SLinus Torvalds {
1541da177e4SLinus Torvalds 	switch (rate) {
1551da177e4SLinus Torvalds 	case 8000:	return ADCCR_SAMPLERATE_8;
1561da177e4SLinus Torvalds 	case 11025:	return ADCCR_SAMPLERATE_11;
1571da177e4SLinus Torvalds 	case 16000:	return ADCCR_SAMPLERATE_16;
1581da177e4SLinus Torvalds 	case 22050:	return ADCCR_SAMPLERATE_22;
1591da177e4SLinus Torvalds 	case 24000:	return ADCCR_SAMPLERATE_24;
1601da177e4SLinus Torvalds 	case 32000:	return ADCCR_SAMPLERATE_32;
1611da177e4SLinus Torvalds 	case 44100:	return ADCCR_SAMPLERATE_44;
1621da177e4SLinus Torvalds 	case 48000:	return ADCCR_SAMPLERATE_48;
1631da177e4SLinus Torvalds 	default:
1641da177e4SLinus Torvalds 			snd_BUG();
1651da177e4SLinus Torvalds 			return ADCCR_SAMPLERATE_8;
1661da177e4SLinus Torvalds 	}
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds 	switch (rate) {
1721da177e4SLinus Torvalds 	case 8000:	return A_ADCCR_SAMPLERATE_8;
1731da177e4SLinus Torvalds 	case 11025:	return A_ADCCR_SAMPLERATE_11;
1741da177e4SLinus Torvalds 	case 12000:	return A_ADCCR_SAMPLERATE_12; /* really supported? */
1751da177e4SLinus Torvalds 	case 16000:	return ADCCR_SAMPLERATE_16;
1761da177e4SLinus Torvalds 	case 22050:	return ADCCR_SAMPLERATE_22;
1771da177e4SLinus Torvalds 	case 24000:	return ADCCR_SAMPLERATE_24;
1781da177e4SLinus Torvalds 	case 32000:	return ADCCR_SAMPLERATE_32;
1791da177e4SLinus Torvalds 	case 44100:	return ADCCR_SAMPLERATE_44;
1801da177e4SLinus Torvalds 	case 48000:	return ADCCR_SAMPLERATE_48;
1811da177e4SLinus Torvalds 	default:
1821da177e4SLinus Torvalds 			snd_BUG();
1831da177e4SLinus Torvalds 			return A_ADCCR_SAMPLERATE_8;
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds static unsigned int emu10k1_calc_pitch_target(unsigned int rate)
1881da177e4SLinus Torvalds {
1891da177e4SLinus Torvalds 	unsigned int pitch_target;
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 	pitch_target = (rate << 8) / 375;
1921da177e4SLinus Torvalds 	pitch_target = (pitch_target >> 1) + (pitch_target & 1);
1931da177e4SLinus Torvalds 	return pitch_target;
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds #define PITCH_48000 0x00004000
1971da177e4SLinus Torvalds #define PITCH_96000 0x00008000
1981da177e4SLinus Torvalds #define PITCH_85000 0x00007155
1991da177e4SLinus Torvalds #define PITCH_80726 0x00006ba2
2001da177e4SLinus Torvalds #define PITCH_67882 0x00005a82
2011da177e4SLinus Torvalds #define PITCH_57081 0x00004c1c
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds static unsigned int emu10k1_select_interprom(unsigned int pitch_target)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds 	if (pitch_target == PITCH_48000)
2061da177e4SLinus Torvalds 		return CCCA_INTERPROM_0;
2071da177e4SLinus Torvalds 	else if (pitch_target < PITCH_48000)
2081da177e4SLinus Torvalds 		return CCCA_INTERPROM_1;
2091da177e4SLinus Torvalds 	else if (pitch_target >= PITCH_96000)
2101da177e4SLinus Torvalds 		return CCCA_INTERPROM_0;
2111da177e4SLinus Torvalds 	else if (pitch_target >= PITCH_85000)
2121da177e4SLinus Torvalds 		return CCCA_INTERPROM_6;
2131da177e4SLinus Torvalds 	else if (pitch_target >= PITCH_80726)
2141da177e4SLinus Torvalds 		return CCCA_INTERPROM_5;
2151da177e4SLinus Torvalds 	else if (pitch_target >= PITCH_67882)
2161da177e4SLinus Torvalds 		return CCCA_INTERPROM_4;
2171da177e4SLinus Torvalds 	else if (pitch_target >= PITCH_57081)
2181da177e4SLinus Torvalds 		return CCCA_INTERPROM_3;
2191da177e4SLinus Torvalds 	else
2201da177e4SLinus Torvalds 		return CCCA_INTERPROM_2;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
223fccd6f31SOswald Buddenhagen static u16 emu10k1_send_target_from_amount(u8 amount)
224fccd6f31SOswald Buddenhagen {
225fccd6f31SOswald Buddenhagen 	static const u8 shifts[8] = { 4, 4, 5, 6, 7, 8, 9, 10 };
226fccd6f31SOswald Buddenhagen 	static const u16 offsets[8] = { 0, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000 };
227fccd6f31SOswald Buddenhagen 	u8 exp;
228fccd6f31SOswald Buddenhagen 
229fccd6f31SOswald Buddenhagen 	if (amount == 0xff)
230fccd6f31SOswald Buddenhagen 		return 0xffff;
231fccd6f31SOswald Buddenhagen 	exp = amount >> 5;
232fccd6f31SOswald Buddenhagen 	return ((amount & 0x1f) << shifts[exp]) + offsets[exp];
233fccd6f31SOswald Buddenhagen }
234fccd6f31SOswald Buddenhagen 
235eb4698f3STakashi Iwai static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
236eb4698f3STakashi Iwai 				       struct snd_emu10k1_voice *evoice,
2379e72666bSOswald Buddenhagen 				       bool w_16, bool stereo,
2381da177e4SLinus Torvalds 				       unsigned int start_addr,
2391da177e4SLinus Torvalds 				       unsigned int end_addr,
2407195fb46SOswald Buddenhagen 				       const unsigned char *send_routing,
2417195fb46SOswald Buddenhagen 				       const unsigned char *send_amount)
2421da177e4SLinus Torvalds {
243eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream = evoice->epcm->substream;
244eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
2457195fb46SOswald Buddenhagen 	unsigned int silent_page;
2469e72666bSOswald Buddenhagen 	int voice;
2471da177e4SLinus Torvalds 	unsigned int pitch_target;
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	voice = evoice->number;
2501da177e4SLinus Torvalds 
251190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model)
252b0dbdaeaSJames Courtier-Dutton 		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
253b0dbdaeaSJames Courtier-Dutton 	else
2541da177e4SLinus Torvalds 		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
25546055699SOswald Buddenhagen 	silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) |
25646055699SOswald Buddenhagen 		      (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
25746055699SOswald Buddenhagen 	snd_emu10k1_ptr_write_multiple(emu, voice,
25846055699SOswald Buddenhagen 		// Not really necessary for the slave, but it doesn't hurt
25946055699SOswald Buddenhagen 		CPF, stereo ? CPF_STEREO_MASK : 0,
26046055699SOswald Buddenhagen 		// Assumption that PT is already 0 so no harm overwriting
26146055699SOswald Buddenhagen 		PTRX, (send_amount[0] << 8) | send_amount[1],
26246055699SOswald Buddenhagen 		// Stereo slaves don't need to have the addresses set, but it doesn't hurt
26346055699SOswald Buddenhagen 		DSL, end_addr | (send_amount[3] << 24),
26446055699SOswald Buddenhagen 		PSST, start_addr | (send_amount[2] << 24),
26546055699SOswald Buddenhagen 		CCCA, emu10k1_select_interprom(pitch_target) |
26646055699SOswald Buddenhagen 		      (w_16 ? 0 : CCCA_8BITSELECT),
26746055699SOswald Buddenhagen 		// Clear filter delay memory
26846055699SOswald Buddenhagen 		Z1, 0,
26946055699SOswald Buddenhagen 		Z2, 0,
27046055699SOswald Buddenhagen 		// Invalidate maps
27146055699SOswald Buddenhagen 		MAPA, silent_page,
27246055699SOswald Buddenhagen 		MAPB, silent_page,
27394dabafeSOswald Buddenhagen 		// Disable filter (in conjunction with CCCA_RESONANCE == 0)
27446055699SOswald Buddenhagen 		VTFT, VTFT_FILTERTARGET_MASK,
27546055699SOswald Buddenhagen 		CVCF, CVCF_CURRENTFILTER_MASK,
27646055699SOswald Buddenhagen 		REGLIST_END);
27746055699SOswald Buddenhagen 	// Setup routing
27846055699SOswald Buddenhagen 	if (emu->audigy) {
27946055699SOswald Buddenhagen 		snd_emu10k1_ptr_write_multiple(emu, voice,
28046055699SOswald Buddenhagen 			A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(send_routing),
28146055699SOswald Buddenhagen 			A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(send_routing),
28246055699SOswald Buddenhagen 			A_SENDAMOUNTS, snd_emu10k1_compose_audigy_sendamounts(send_amount),
28346055699SOswald Buddenhagen 			REGLIST_END);
284fccd6f31SOswald Buddenhagen 		for (int i = 0; i < 4; i++) {
285fccd6f31SOswald Buddenhagen 			u32 aml = emu10k1_send_target_from_amount(send_amount[2 * i]);
286fccd6f31SOswald Buddenhagen 			u32 amh = emu10k1_send_target_from_amount(send_amount[2 * i + 1]);
287fccd6f31SOswald Buddenhagen 			snd_emu10k1_ptr_write(emu, A_CSBA + i, voice, (amh << 16) | aml);
288fccd6f31SOswald Buddenhagen 		}
28946055699SOswald Buddenhagen 	} else {
29046055699SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, FXRT, voice,
29146055699SOswald Buddenhagen 				      snd_emu10k1_compose_send_routing(send_routing));
29246055699SOswald Buddenhagen 	}
2931da177e4SLinus Torvalds 
29482a9fa6eSOswald Buddenhagen 	emu->voices[voice].dirty = 1;
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds 
297f5192e33SOswald Buddenhagen static void snd_emu10k1_pcm_init_voices(struct snd_emu10k1 *emu,
298f5192e33SOswald Buddenhagen 					struct snd_emu10k1_voice *evoice,
299f5192e33SOswald Buddenhagen 					bool w_16, bool stereo,
300f5192e33SOswald Buddenhagen 					unsigned int start_addr,
301f5192e33SOswald Buddenhagen 					unsigned int end_addr,
302f5192e33SOswald Buddenhagen 					struct snd_emu10k1_pcm_mixer *mix)
303f5192e33SOswald Buddenhagen {
3047195fb46SOswald Buddenhagen 	unsigned long flags;
3057195fb46SOswald Buddenhagen 
3067195fb46SOswald Buddenhagen 	spin_lock_irqsave(&emu->reg_lock, flags);
3077195fb46SOswald Buddenhagen 	snd_emu10k1_pcm_init_voice(emu, evoice, w_16, stereo,
3087195fb46SOswald Buddenhagen 				   start_addr, end_addr,
3097195fb46SOswald Buddenhagen 				   &mix->send_routing[stereo][0],
3107195fb46SOswald Buddenhagen 				   &mix->send_volume[stereo][0]);
311f5192e33SOswald Buddenhagen 	if (stereo)
3127195fb46SOswald Buddenhagen 		snd_emu10k1_pcm_init_voice(emu, evoice + 1, w_16, true,
3137195fb46SOswald Buddenhagen 					   start_addr, end_addr,
3147195fb46SOswald Buddenhagen 					   &mix->send_routing[2][0],
3157195fb46SOswald Buddenhagen 					   &mix->send_volume[2][0]);
3167195fb46SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->reg_lock, flags);
317f5192e33SOswald Buddenhagen }
318f5192e33SOswald Buddenhagen 
319f5192e33SOswald Buddenhagen static void snd_emu10k1_pcm_init_extra_voice(struct snd_emu10k1 *emu,
320f5192e33SOswald Buddenhagen 					     struct snd_emu10k1_voice *evoice,
321f5192e33SOswald Buddenhagen 					     bool w_16,
322f5192e33SOswald Buddenhagen 					     unsigned int start_addr,
323f5192e33SOswald Buddenhagen 					     unsigned int end_addr)
324f5192e33SOswald Buddenhagen {
3257195fb46SOswald Buddenhagen 	static const unsigned char send_routing[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
3267195fb46SOswald Buddenhagen 	static const unsigned char send_amount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
3277195fb46SOswald Buddenhagen 
3287195fb46SOswald Buddenhagen 	snd_emu10k1_pcm_init_voice(emu, evoice, w_16, false,
3297195fb46SOswald Buddenhagen 				   start_addr, end_addr,
3307195fb46SOswald Buddenhagen 				   send_routing, send_amount);
331f5192e33SOswald Buddenhagen }
332f5192e33SOswald Buddenhagen 
333eb4698f3STakashi Iwai static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream,
334eb4698f3STakashi Iwai 					  struct snd_pcm_hw_params *hw_params)
3351da177e4SLinus Torvalds {
336eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
337eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
338eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
33904f8773aSMaciej S. Szmigiero 	size_t alloc_size;
340a915d604SOswald Buddenhagen 	int type, channels, count;
3411da177e4SLinus Torvalds 	int err;
3421da177e4SLinus Torvalds 
343a915d604SOswald Buddenhagen 	if (epcm->type == PLAYBACK_EMUVOICE) {
344a915d604SOswald Buddenhagen 		type = EMU10K1_PCM;
345a915d604SOswald Buddenhagen 		channels = 1;
346a915d604SOswald Buddenhagen 		count = params_channels(hw_params);
347a915d604SOswald Buddenhagen 	} else {
348a915d604SOswald Buddenhagen 		type = EMU10K1_EFX;
349a915d604SOswald Buddenhagen 		channels = params_channels(hw_params);
350a915d604SOswald Buddenhagen 		count = 1;
351a915d604SOswald Buddenhagen 	}
352a915d604SOswald Buddenhagen 	err = snd_emu10k1_pcm_channel_alloc(epcm, type, count, channels);
35312bda107STakashi Iwai 	if (err < 0)
3541da177e4SLinus Torvalds 		return err;
35504f8773aSMaciej S. Szmigiero 
35604f8773aSMaciej S. Szmigiero 	alloc_size = params_buffer_bytes(hw_params);
35704f8773aSMaciej S. Szmigiero 	if (emu->iommu_workaround)
35804f8773aSMaciej S. Szmigiero 		alloc_size += EMUPAGESIZE;
35904f8773aSMaciej S. Szmigiero 	err = snd_pcm_lib_malloc_pages(substream, alloc_size);
36004f8773aSMaciej S. Szmigiero 	if (err < 0)
3611da177e4SLinus Torvalds 		return err;
36204f8773aSMaciej S. Szmigiero 	if (emu->iommu_workaround && runtime->dma_bytes >= EMUPAGESIZE)
36304f8773aSMaciej S. Szmigiero 		runtime->dma_bytes -= EMUPAGESIZE;
3641da177e4SLinus Torvalds 	if (err > 0) {	/* change */
365e017fa57STakashi Iwai 		int mapped;
3661da177e4SLinus Torvalds 		if (epcm->memblk != NULL)
3671da177e4SLinus Torvalds 			snd_emu10k1_free_pages(emu, epcm->memblk);
368e017fa57STakashi Iwai 		epcm->memblk = snd_emu10k1_alloc_pages(emu, substream);
3691da177e4SLinus Torvalds 		epcm->start_addr = 0;
370e017fa57STakashi Iwai 		if (! epcm->memblk)
3711da177e4SLinus Torvalds 			return -ENOMEM;
372eb4698f3STakashi Iwai 		mapped = ((struct snd_emu10k1_memblk *)epcm->memblk)->mapped_page;
373e017fa57STakashi Iwai 		if (mapped < 0)
374e017fa57STakashi Iwai 			return -ENOMEM;
375e017fa57STakashi Iwai 		epcm->start_addr = mapped << PAGE_SHIFT;
3761da177e4SLinus Torvalds 	}
3771da177e4SLinus Torvalds 	return 0;
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds 
380eb4698f3STakashi Iwai static int snd_emu10k1_playback_hw_free(struct snd_pcm_substream *substream)
3811da177e4SLinus Torvalds {
382eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
383eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
384eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	if (runtime->private_data == NULL)
3871da177e4SLinus Torvalds 		return 0;
3881da177e4SLinus Torvalds 	epcm = runtime->private_data;
3891da177e4SLinus Torvalds 	if (epcm->extra) {
3901da177e4SLinus Torvalds 		snd_emu10k1_voice_free(epcm->emu, epcm->extra);
3911da177e4SLinus Torvalds 		epcm->extra = NULL;
3921da177e4SLinus Torvalds 	}
393bdb3b567SOswald Buddenhagen 	snd_emu10k1_pcm_free_voices(epcm);
3941da177e4SLinus Torvalds 	if (epcm->memblk) {
3951da177e4SLinus Torvalds 		snd_emu10k1_free_pages(emu, epcm->memblk);
3961da177e4SLinus Torvalds 		epcm->memblk = NULL;
3971da177e4SLinus Torvalds 		epcm->start_addr = 0;
3981da177e4SLinus Torvalds 	}
3991da177e4SLinus Torvalds 	snd_pcm_lib_free_pages(substream);
4001da177e4SLinus Torvalds 	return 0;
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
403eb4698f3STakashi Iwai static int snd_emu10k1_playback_prepare(struct snd_pcm_substream *substream)
4041da177e4SLinus Torvalds {
405eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
406eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
407eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
408af7fd027SOswald Buddenhagen 	bool w_16 = snd_pcm_format_width(runtime->format) == 16;
409af7fd027SOswald Buddenhagen 	bool stereo = runtime->channels == 2;
4101da177e4SLinus Torvalds 	unsigned int start_addr, end_addr;
4111da177e4SLinus Torvalds 
412af7fd027SOswald Buddenhagen 	start_addr = epcm->start_addr >> w_16;
413af7fd027SOswald Buddenhagen 	end_addr = start_addr + runtime->period_size;
414f5192e33SOswald Buddenhagen 	snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, w_16,
415f5192e33SOswald Buddenhagen 					 start_addr, end_addr);
416af7fd027SOswald Buddenhagen 	start_addr >>= stereo;
417fa75064dSOswald Buddenhagen 	epcm->ccca_start_addr = start_addr;
418af7fd027SOswald Buddenhagen 	end_addr = start_addr + runtime->buffer_size;
419f5192e33SOswald Buddenhagen 	snd_emu10k1_pcm_init_voices(emu, epcm->voices[0], w_16, stereo,
4201da177e4SLinus Torvalds 				    start_addr, end_addr,
4211da177e4SLinus Torvalds 				    &emu->pcm_mixer[substream->number]);
422f5192e33SOswald Buddenhagen 
4231da177e4SLinus Torvalds 	return 0;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds 
426eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_prepare(struct snd_pcm_substream *substream)
4271da177e4SLinus Torvalds {
428eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
429eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
430eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
431af7fd027SOswald Buddenhagen 	unsigned int start_addr;
4321da177e4SLinus Torvalds 	unsigned int channel_size;
4331da177e4SLinus Torvalds 	int i;
4341da177e4SLinus Torvalds 
435af7fd027SOswald Buddenhagen 	start_addr = epcm->start_addr >> 1;  // 16-bit voices
4361da177e4SLinus Torvalds 
437af7fd027SOswald Buddenhagen 	channel_size = runtime->buffer_size;
4381da177e4SLinus Torvalds 
439f5192e33SOswald Buddenhagen 	snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, true,
440f5192e33SOswald Buddenhagen 					 start_addr, start_addr + (channel_size / 2));
4411da177e4SLinus Torvalds 
442fa75064dSOswald Buddenhagen 	epcm->ccca_start_addr = start_addr;
443fa75064dSOswald Buddenhagen 	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
4447195fb46SOswald Buddenhagen 		snd_emu10k1_pcm_init_voices(emu, epcm->voices[i], true, false,
4451da177e4SLinus Torvalds 					    start_addr, start_addr + channel_size,
4461da177e4SLinus Torvalds 					    &emu->efx_pcm_mixer[i]);
4471da177e4SLinus Torvalds 		start_addr += channel_size;
4481da177e4SLinus Torvalds 	}
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 	return 0;
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds 
4537c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_efx_playback =
4541da177e4SLinus Torvalds {
4551da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED |
4561da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
45709668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
4581da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
4591da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
4601da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_48000,
4611da177e4SLinus Torvalds 	.rate_min =		48000,
4621da177e4SLinus Torvalds 	.rate_max =		48000,
4631da177e4SLinus Torvalds 	.channels_min =		NUM_EFX_PLAYBACK,
4641da177e4SLinus Torvalds 	.channels_max =		NUM_EFX_PLAYBACK,
4650be0a62fSOswald Buddenhagen 	.buffer_bytes_max =	(128*1024),
4660be0a62fSOswald Buddenhagen 	.period_bytes_max =	(128*1024),
4671da177e4SLinus Torvalds 	.periods_min =		2,
4681da177e4SLinus Torvalds 	.periods_max =		2,
4691da177e4SLinus Torvalds 	.fifo_size =		0,
4701da177e4SLinus Torvalds };
4711da177e4SLinus Torvalds 
472eb4698f3STakashi Iwai static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream)
4731da177e4SLinus Torvalds {
474eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
475eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
476eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
4771da177e4SLinus Torvalds 	int idx;
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds 	/* zeroing the buffer size will stop capture */
4801da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);
4811da177e4SLinus Torvalds 	switch (epcm->type) {
4821da177e4SLinus Torvalds 	case CAPTURE_AC97ADC:
4831da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);
4841da177e4SLinus Torvalds 		break;
4851da177e4SLinus Torvalds 	case CAPTURE_EFX:
4861da177e4SLinus Torvalds 		if (emu->audigy) {
48746055699SOswald Buddenhagen 			snd_emu10k1_ptr_write_multiple(emu, 0,
48846055699SOswald Buddenhagen 				A_FXWC1, 0,
48946055699SOswald Buddenhagen 				A_FXWC2, 0,
49046055699SOswald Buddenhagen 				REGLIST_END);
4911da177e4SLinus Torvalds 		} else
4921da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, FXWC, 0, 0);
4931da177e4SLinus Torvalds 		break;
4941da177e4SLinus Torvalds 	default:
4951da177e4SLinus Torvalds 		break;
4961da177e4SLinus Torvalds 	}
4971da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, epcm->capture_ba_reg, 0, runtime->dma_addr);
4981da177e4SLinus Torvalds 	epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream);
4991da177e4SLinus Torvalds 	epcm->capture_bs_val = 0;
5001da177e4SLinus Torvalds 	for (idx = 0; idx < 31; idx++) {
5011da177e4SLinus Torvalds 		if (capture_period_sizes[idx] == epcm->capture_bufsize) {
5021da177e4SLinus Torvalds 			epcm->capture_bs_val = idx + 1;
5031da177e4SLinus Torvalds 			break;
5041da177e4SLinus Torvalds 		}
5051da177e4SLinus Torvalds 	}
5061da177e4SLinus Torvalds 	if (epcm->capture_bs_val == 0) {
5071da177e4SLinus Torvalds 		snd_BUG();
5081da177e4SLinus Torvalds 		epcm->capture_bs_val++;
5091da177e4SLinus Torvalds 	}
5101da177e4SLinus Torvalds 	if (epcm->type == CAPTURE_AC97ADC) {
5111da177e4SLinus Torvalds 		epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
5121da177e4SLinus Torvalds 		if (runtime->channels > 1)
5131da177e4SLinus Torvalds 			epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
5141da177e4SLinus Torvalds 		epcm->capture_cr_val |= emu->audigy ?
5151da177e4SLinus Torvalds 			snd_emu10k1_audigy_capture_rate_reg(runtime->rate) :
5161da177e4SLinus Torvalds 			snd_emu10k1_capture_rate_reg(runtime->rate);
5171da177e4SLinus Torvalds 	}
5181da177e4SLinus Torvalds 	return 0;
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds 
5219581128aSOswald Buddenhagen static void snd_emu10k1_playback_fill_cache(struct snd_emu10k1 *emu,
5229581128aSOswald Buddenhagen 					    unsigned voice,
5239581128aSOswald Buddenhagen 					    u32 sample, bool stereo)
5241da177e4SLinus Torvalds {
5255b1cd21fSOswald Buddenhagen 	u32 ccr;
5261da177e4SLinus Torvalds 
5275b1cd21fSOswald Buddenhagen 	// We assume that the cache is resting at this point (i.e.,
5285b1cd21fSOswald Buddenhagen 	// CCR_CACHEINVALIDSIZE is very small).
5295b1cd21fSOswald Buddenhagen 
5305b1cd21fSOswald Buddenhagen 	// Clear leading frames. For simplicitly, this does too much,
5315b1cd21fSOswald Buddenhagen 	// except for 16-bit stereo. And the interpolator will actually
5325b1cd21fSOswald Buddenhagen 	// access them at all only when we're pitch-shifting.
5335b1cd21fSOswald Buddenhagen 	for (int i = 0; i < 3; i++)
5341da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample);
5355b1cd21fSOswald Buddenhagen 
5365b1cd21fSOswald Buddenhagen 	// Fill cache
5375b1cd21fSOswald Buddenhagen 	ccr = (64 - 3) << REG_SHIFT(CCR_CACHEINVALIDSIZE);
5381da177e4SLinus Torvalds 	if (stereo) {
5395b1cd21fSOswald Buddenhagen 		// The engine goes haywire if CCR_READADDRESS is out of sync
5405b1cd21fSOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, CCR, voice + 1, ccr);
5411da177e4SLinus Torvalds 	}
5425b1cd21fSOswald Buddenhagen 	snd_emu10k1_ptr_write(emu, CCR, voice, ccr);
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds 
5459581128aSOswald Buddenhagen static void snd_emu10k1_playback_prepare_voices(struct snd_emu10k1 *emu,
5469581128aSOswald Buddenhagen 						struct snd_emu10k1_pcm *epcm,
5479581128aSOswald Buddenhagen 						bool w_16, bool stereo,
5489581128aSOswald Buddenhagen 						int channels)
5499581128aSOswald Buddenhagen {
550fa75064dSOswald Buddenhagen 	struct snd_pcm_substream *substream = epcm->substream;
551fa75064dSOswald Buddenhagen 	struct snd_pcm_runtime *runtime = substream->runtime;
552fa75064dSOswald Buddenhagen 	unsigned eloop_start = epcm->start_addr >> w_16;
553fa75064dSOswald Buddenhagen 	unsigned loop_start = eloop_start >> stereo;
554fa75064dSOswald Buddenhagen 	unsigned eloop_size = runtime->period_size;
555fa75064dSOswald Buddenhagen 	unsigned loop_size = runtime->buffer_size;
5569581128aSOswald Buddenhagen 	u32 sample = w_16 ? 0 : 0x80808080;
5579581128aSOswald Buddenhagen 
558fa75064dSOswald Buddenhagen 	// To make the playback actually start at the 1st frame,
559fa75064dSOswald Buddenhagen 	// we need to compensate for two circumstances:
560fa75064dSOswald Buddenhagen 	// - The actual position is delayed by the cache size (64 frames)
561fa75064dSOswald Buddenhagen 	// - The interpolator is centered around the 4th frame
562fa75064dSOswald Buddenhagen 	loop_start += 64 - 3;
5639581128aSOswald Buddenhagen 	for (int i = 0; i < channels; i++) {
5649581128aSOswald Buddenhagen 		unsigned voice = epcm->voices[i]->number;
565fa75064dSOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, voice, loop_start);
566fa75064dSOswald Buddenhagen 		loop_start += loop_size;
5679581128aSOswald Buddenhagen 		snd_emu10k1_playback_fill_cache(emu, voice, sample, stereo);
5689581128aSOswald Buddenhagen 	}
5699581128aSOswald Buddenhagen 
570fa75064dSOswald Buddenhagen 	// The interrupt is triggered when CCCA_CURRADDR (CA) wraps around,
571fa75064dSOswald Buddenhagen 	// which is ahead of the actual playback position, so the interrupt
572fa75064dSOswald Buddenhagen 	// source needs to be delayed.
573fa75064dSOswald Buddenhagen 	//
574fa75064dSOswald Buddenhagen 	// In principle, this wouldn't need to be the cache's entire size - in
575fa75064dSOswald Buddenhagen 	// practice, CCR_CACHEINVALIDSIZE (CIS) > `fetch threshold` has never
576fa75064dSOswald Buddenhagen 	// been observed, and assuming 40 _bytes_ should be safe.
577fa75064dSOswald Buddenhagen 	//
578fa75064dSOswald Buddenhagen 	// The cache fills are somewhat random, which makes it impossible to
579fa75064dSOswald Buddenhagen 	// align them with the interrupts. This makes a non-delayed interrupt
580fa75064dSOswald Buddenhagen 	// source not practical, as the interrupt handler would have to wait
581fa75064dSOswald Buddenhagen 	// for (CA - CIS) >= period_boundary for every channel in the stream.
582fa75064dSOswald Buddenhagen 	//
583fa75064dSOswald Buddenhagen 	// This is why all other (open) drivers for these chips use timer-based
584fa75064dSOswald Buddenhagen 	// interrupts.
585fa75064dSOswald Buddenhagen 	//
586fa75064dSOswald Buddenhagen 	eloop_start += eloop_size - 3;
587fa75064dSOswald Buddenhagen 	snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, epcm->extra->number, eloop_start);
588fa75064dSOswald Buddenhagen 
5899581128aSOswald Buddenhagen 	// It takes a moment until the cache fills complete,
5909581128aSOswald Buddenhagen 	// but the unmuting takes long enough for that.
5919581128aSOswald Buddenhagen }
5929581128aSOswald Buddenhagen 
59377e067d0SOswald Buddenhagen static void snd_emu10k1_playback_commit_volume(struct snd_emu10k1 *emu,
59477e067d0SOswald Buddenhagen 					       struct snd_emu10k1_voice *evoice,
59577e067d0SOswald Buddenhagen 					       unsigned int vattn)
59677e067d0SOswald Buddenhagen {
59746055699SOswald Buddenhagen 	snd_emu10k1_ptr_write_multiple(emu, evoice->number,
59846055699SOswald Buddenhagen 		VTFT, vattn | VTFT_FILTERTARGET_MASK,
59946055699SOswald Buddenhagen 		CVCF, vattn | CVCF_CURRENTFILTER_MASK,
60046055699SOswald Buddenhagen 		REGLIST_END);
60177e067d0SOswald Buddenhagen }
60277e067d0SOswald Buddenhagen 
60377e067d0SOswald Buddenhagen static void snd_emu10k1_playback_unmute_voice(struct snd_emu10k1 *emu,
60477e067d0SOswald Buddenhagen 					      struct snd_emu10k1_voice *evoice,
6059e72666bSOswald Buddenhagen 					      bool stereo, bool master,
606eb4698f3STakashi Iwai 					      struct snd_emu10k1_pcm_mixer *mix)
6071da177e4SLinus Torvalds {
60894dabafeSOswald Buddenhagen 	unsigned int vattn;
60977e067d0SOswald Buddenhagen 	unsigned int tmp;
6101da177e4SLinus Torvalds 
6119e72666bSOswald Buddenhagen 	tmp = stereo ? (master ? 1 : 2) : 0;
61277e067d0SOswald Buddenhagen 	vattn = mix->attn[tmp] << 16;
61377e067d0SOswald Buddenhagen 	snd_emu10k1_playback_commit_volume(emu, evoice, vattn);
61477e067d0SOswald Buddenhagen }
61577e067d0SOswald Buddenhagen 
616f5192e33SOswald Buddenhagen static void snd_emu10k1_playback_unmute_voices(struct snd_emu10k1 *emu,
617f5192e33SOswald Buddenhagen 					       struct snd_emu10k1_voice *evoice,
618f5192e33SOswald Buddenhagen 					       bool stereo,
619f5192e33SOswald Buddenhagen 					       struct snd_emu10k1_pcm_mixer *mix)
620f5192e33SOswald Buddenhagen {
621f5192e33SOswald Buddenhagen 	snd_emu10k1_playback_unmute_voice(emu, evoice, stereo, true, mix);
622f5192e33SOswald Buddenhagen 	if (stereo)
623f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_unmute_voice(emu, evoice + 1, true, false, mix);
624f5192e33SOswald Buddenhagen }
625f5192e33SOswald Buddenhagen 
62677e067d0SOswald Buddenhagen static void snd_emu10k1_playback_mute_voice(struct snd_emu10k1 *emu,
62777e067d0SOswald Buddenhagen 					    struct snd_emu10k1_voice *evoice)
62877e067d0SOswald Buddenhagen {
62977e067d0SOswald Buddenhagen 	snd_emu10k1_playback_commit_volume(emu, evoice, 0);
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds 
632f5192e33SOswald Buddenhagen static void snd_emu10k1_playback_mute_voices(struct snd_emu10k1 *emu,
633f5192e33SOswald Buddenhagen 					     struct snd_emu10k1_voice *evoice,
634f5192e33SOswald Buddenhagen 					     bool stereo)
635f5192e33SOswald Buddenhagen {
636f5192e33SOswald Buddenhagen 	snd_emu10k1_playback_mute_voice(emu, evoice);
637f5192e33SOswald Buddenhagen 	if (stereo)
638f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_mute_voice(emu, evoice + 1);
639f5192e33SOswald Buddenhagen }
640f5192e33SOswald Buddenhagen 
64108e55ae9SOswald Buddenhagen static void snd_emu10k1_playback_commit_pitch(struct snd_emu10k1 *emu,
64208e55ae9SOswald Buddenhagen 					      u32 voice, u32 pitch_target)
64308e55ae9SOswald Buddenhagen {
64408e55ae9SOswald Buddenhagen 	u32 ptrx = snd_emu10k1_ptr_read(emu, PTRX, voice);
64508e55ae9SOswald Buddenhagen 	u32 cpf = snd_emu10k1_ptr_read(emu, CPF, voice);
64608e55ae9SOswald Buddenhagen 	snd_emu10k1_ptr_write_multiple(emu, voice,
64708e55ae9SOswald Buddenhagen 		PTRX, (ptrx & ~PTRX_PITCHTARGET_MASK) | pitch_target,
64808e55ae9SOswald Buddenhagen 		CPF, (cpf & ~(CPF_CURRENTPITCH_MASK | CPF_FRACADDRESS_MASK)) | pitch_target,
64908e55ae9SOswald Buddenhagen 		REGLIST_END);
65008e55ae9SOswald Buddenhagen }
65108e55ae9SOswald Buddenhagen 
65235a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu,
65377e067d0SOswald Buddenhagen 					       struct snd_emu10k1_voice *evoice)
6541da177e4SLinus Torvalds {
655eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream;
656eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime;
65794dabafeSOswald Buddenhagen 	unsigned int voice, pitch_target;
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds 	substream = evoice->epcm->substream;
6601da177e4SLinus Torvalds 	runtime = substream->runtime;
6611da177e4SLinus Torvalds 	voice = evoice->number;
6621da177e4SLinus Torvalds 
663190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model)
664b0dbdaeaSJames Courtier-Dutton 		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
665b0dbdaeaSJames Courtier-Dutton 	else
6661da177e4SLinus Torvalds 		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
66708e55ae9SOswald Buddenhagen 	snd_emu10k1_playback_commit_pitch(emu, voice, pitch_target << 16);
6681da177e4SLinus Torvalds }
6691da177e4SLinus Torvalds 
67035a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu,
67135a60d1eSOswald Buddenhagen 					    struct snd_emu10k1_voice *evoice)
6721da177e4SLinus Torvalds {
6731da177e4SLinus Torvalds 	unsigned int voice;
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds 	voice = evoice->number;
67608e55ae9SOswald Buddenhagen 	snd_emu10k1_playback_commit_pitch(emu, voice, 0);
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds 
67935a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_set_running(struct snd_emu10k1 *emu,
68035a60d1eSOswald Buddenhagen 					     struct snd_emu10k1_pcm *epcm)
68135a60d1eSOswald Buddenhagen {
68235a60d1eSOswald Buddenhagen 	epcm->running = 1;
68335a60d1eSOswald Buddenhagen 	snd_emu10k1_voice_intr_enable(emu, epcm->extra->number);
68435a60d1eSOswald Buddenhagen }
68535a60d1eSOswald Buddenhagen 
68635a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_set_stopped(struct snd_emu10k1 *emu,
68735a60d1eSOswald Buddenhagen 					      struct snd_emu10k1_pcm *epcm)
68835a60d1eSOswald Buddenhagen {
68935a60d1eSOswald Buddenhagen 	snd_emu10k1_voice_intr_disable(emu, epcm->extra->number);
69035a60d1eSOswald Buddenhagen 	epcm->running = 0;
69135a60d1eSOswald Buddenhagen }
69235a60d1eSOswald Buddenhagen 
693eb4698f3STakashi Iwai static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
6941da177e4SLinus Torvalds 				        int cmd)
6951da177e4SLinus Torvalds {
696eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
697eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
698eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
699eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
7009e72666bSOswald Buddenhagen 	bool w_16 = snd_pcm_format_width(runtime->format) == 16;
7019e72666bSOswald Buddenhagen 	bool stereo = runtime->channels == 2;
7021da177e4SLinus Torvalds 	int result = 0;
7031da177e4SLinus Torvalds 
70428a97c19STakashi Iwai 	/*
7056f002b02STakashi Iwai 	dev_dbg(emu->card->dev,
7066f002b02STakashi Iwai 		"trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
70728a97c19STakashi Iwai 	       (int)emu, cmd, substream->ops->pointer(substream))
70828a97c19STakashi Iwai 	*/
7091da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
7101da177e4SLinus Torvalds 	switch (cmd) {
7111da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
7129581128aSOswald Buddenhagen 		snd_emu10k1_playback_prepare_voices(emu, epcm, w_16, stereo, 1);
713c0dbbdadSGustavo A. R. Silva 		fallthrough;
7141da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
71509668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
7161da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[substream->number];
717f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_unmute_voices(emu, epcm->voices[0], stereo, mix);
71835a60d1eSOswald Buddenhagen 		snd_emu10k1_playback_set_running(emu, epcm);
71977e067d0SOswald Buddenhagen 		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0]);
72077e067d0SOswald Buddenhagen 		snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
7211da177e4SLinus Torvalds 		break;
7221da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
7231da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
72409668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
7251da177e4SLinus Torvalds 		snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]);
7261da177e4SLinus Torvalds 		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
72735a60d1eSOswald Buddenhagen 		snd_emu10k1_playback_set_stopped(emu, epcm);
728f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_mute_voices(emu, epcm->voices[0], stereo);
7291da177e4SLinus Torvalds 		break;
7301da177e4SLinus Torvalds 	default:
7311da177e4SLinus Torvalds 		result = -EINVAL;
7321da177e4SLinus Torvalds 		break;
7331da177e4SLinus Torvalds 	}
7341da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
7351da177e4SLinus Torvalds 	return result;
7361da177e4SLinus Torvalds }
7371da177e4SLinus Torvalds 
738eb4698f3STakashi Iwai static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
7391da177e4SLinus Torvalds 				       int cmd)
7401da177e4SLinus Torvalds {
741eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
742eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
743eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
7441da177e4SLinus Torvalds 	int result = 0;
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
7471da177e4SLinus Torvalds 	switch (cmd) {
7481da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
74909668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
7509f4bd5ddSJames Courtier-Dutton 		/* hmm this should cause full and half full interrupt to be raised? */
7511da177e4SLinus Torvalds 		outl(epcm->capture_ipr, emu->port + IPR);
7521da177e4SLinus Torvalds 		snd_emu10k1_intr_enable(emu, epcm->capture_inte);
75328a97c19STakashi Iwai 		/*
7546f002b02STakashi Iwai 		dev_dbg(emu->card->dev, "adccr = 0x%x, adcbs = 0x%x\n",
75528a97c19STakashi Iwai 		       epcm->adccr, epcm->adcbs);
75628a97c19STakashi Iwai 		*/
7571da177e4SLinus Torvalds 		switch (epcm->type) {
7581da177e4SLinus Torvalds 		case CAPTURE_AC97ADC:
7591da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val);
7601da177e4SLinus Torvalds 			break;
7611da177e4SLinus Torvalds 		case CAPTURE_EFX:
7621da177e4SLinus Torvalds 			if (emu->audigy) {
76346055699SOswald Buddenhagen 				snd_emu10k1_ptr_write_multiple(emu, 0,
76446055699SOswald Buddenhagen 					A_FXWC1, epcm->capture_cr_val,
76546055699SOswald Buddenhagen 					A_FXWC2, epcm->capture_cr_val2,
76646055699SOswald Buddenhagen 					REGLIST_END);
7676f002b02STakashi Iwai 				dev_dbg(emu->card->dev,
7686f002b02STakashi Iwai 					"cr_val=0x%x, cr_val2=0x%x\n",
7696f002b02STakashi Iwai 					epcm->capture_cr_val,
7706f002b02STakashi Iwai 					epcm->capture_cr_val2);
7711da177e4SLinus Torvalds 			} else
7721da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);
7731da177e4SLinus Torvalds 			break;
7741da177e4SLinus Torvalds 		default:
7751da177e4SLinus Torvalds 			break;
7761da177e4SLinus Torvalds 		}
7771da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, epcm->capture_bs_val);
7781da177e4SLinus Torvalds 		epcm->running = 1;
7791da177e4SLinus Torvalds 		epcm->first_ptr = 1;
7801da177e4SLinus Torvalds 		break;
7811da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
78209668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
7831da177e4SLinus Torvalds 		epcm->running = 0;
7841da177e4SLinus Torvalds 		snd_emu10k1_intr_disable(emu, epcm->capture_inte);
7851da177e4SLinus Torvalds 		outl(epcm->capture_ipr, emu->port + IPR);
7861da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);
7871da177e4SLinus Torvalds 		switch (epcm->type) {
7881da177e4SLinus Torvalds 		case CAPTURE_AC97ADC:
7891da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);
7901da177e4SLinus Torvalds 			break;
7911da177e4SLinus Torvalds 		case CAPTURE_EFX:
7921da177e4SLinus Torvalds 			if (emu->audigy) {
79346055699SOswald Buddenhagen 				snd_emu10k1_ptr_write_multiple(emu, 0,
79446055699SOswald Buddenhagen 					A_FXWC1, 0,
79546055699SOswald Buddenhagen 					A_FXWC2, 0,
79646055699SOswald Buddenhagen 					REGLIST_END);
7971da177e4SLinus Torvalds 			} else
7981da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, FXWC, 0, 0);
7991da177e4SLinus Torvalds 			break;
8001da177e4SLinus Torvalds 		default:
8011da177e4SLinus Torvalds 			break;
8021da177e4SLinus Torvalds 		}
8031da177e4SLinus Torvalds 		break;
8041da177e4SLinus Torvalds 	default:
8051da177e4SLinus Torvalds 		result = -EINVAL;
8061da177e4SLinus Torvalds 	}
8071da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
8081da177e4SLinus Torvalds 	return result;
8091da177e4SLinus Torvalds }
8101da177e4SLinus Torvalds 
811eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *substream)
8121da177e4SLinus Torvalds {
813eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
814eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
815eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
816fa75064dSOswald Buddenhagen 	int ptr;
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 	if (!epcm->running)
8191da177e4SLinus Torvalds 		return 0;
820fa75064dSOswald Buddenhagen 
8211da177e4SLinus Torvalds 	ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff;
822fa75064dSOswald Buddenhagen 	ptr -= epcm->ccca_start_addr;
823fa75064dSOswald Buddenhagen 
824fa75064dSOswald Buddenhagen 	// This is the size of the whole cache minus the interpolator read-ahead,
825fa75064dSOswald Buddenhagen 	// which leads us to the actual playback position.
826fa75064dSOswald Buddenhagen 	//
827fa75064dSOswald Buddenhagen 	// The cache is constantly kept mostly filled, so in principle we could
828fa75064dSOswald Buddenhagen 	// return a more advanced position representing how far the hardware has
829fa75064dSOswald Buddenhagen 	// already read the buffer, and set runtime->delay accordingly. However,
830fa75064dSOswald Buddenhagen 	// this would be slightly different for every channel (and remarkably slow
831fa75064dSOswald Buddenhagen 	// to obtain), so only a fixed worst-case value would be practical.
832fa75064dSOswald Buddenhagen 	//
833fa75064dSOswald Buddenhagen 	ptr -= 64 - 3;
834fa75064dSOswald Buddenhagen 	if (ptr < 0)
8351da177e4SLinus Torvalds 		ptr += runtime->buffer_size;
836fa75064dSOswald Buddenhagen 
83728a97c19STakashi Iwai 	/*
8386f002b02STakashi Iwai 	dev_dbg(emu->card->dev,
83956385a12SJaroslav Kysela 	       "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
84056385a12SJaroslav Kysela 	       (long)ptr, (long)runtime->buffer_size,
84156385a12SJaroslav Kysela 	       (long)runtime->period_size);
84228a97c19STakashi Iwai 	*/
8431da177e4SLinus Torvalds 	return ptr;
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds 
847eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
8481da177e4SLinus Torvalds 				        int cmd)
8491da177e4SLinus Torvalds {
850eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
851eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
852eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
8531da177e4SLinus Torvalds 	int i;
8541da177e4SLinus Torvalds 	int result = 0;
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
8571da177e4SLinus Torvalds 	switch (cmd) {
8581da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
8599581128aSOswald Buddenhagen 		snd_emu10k1_playback_prepare_voices(emu, epcm, true, false, NUM_EFX_PLAYBACK);
860c0dbbdadSGustavo A. R. Silva 		fallthrough;
8611da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
86209668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
86377e067d0SOswald Buddenhagen 		for (i = 0; i < NUM_EFX_PLAYBACK; i++)
8649e72666bSOswald Buddenhagen 			snd_emu10k1_playback_unmute_voice(emu, epcm->voices[i], false, true,
8651da177e4SLinus Torvalds 							  &emu->efx_pcm_mixer[i]);
86677e067d0SOswald Buddenhagen 
86735a60d1eSOswald Buddenhagen 		snd_emu10k1_playback_set_running(emu, epcm);
86835a60d1eSOswald Buddenhagen 		for (i = 0; i < NUM_EFX_PLAYBACK; i++)
86977e067d0SOswald Buddenhagen 			snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i]);
87077e067d0SOswald Buddenhagen 		snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
8711da177e4SLinus Torvalds 		break;
87209668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
8731da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
8741da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
8751da177e4SLinus Torvalds 		for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
8761da177e4SLinus Torvalds 			snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]);
8771da177e4SLinus Torvalds 		}
8781da177e4SLinus Torvalds 		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
87935a60d1eSOswald Buddenhagen 		snd_emu10k1_playback_set_stopped(emu, epcm);
88077e067d0SOswald Buddenhagen 
88177e067d0SOswald Buddenhagen 		for (i = 0; i < NUM_EFX_PLAYBACK; i++)
88277e067d0SOswald Buddenhagen 			snd_emu10k1_playback_mute_voice(emu, epcm->voices[i]);
8831da177e4SLinus Torvalds 		break;
8841da177e4SLinus Torvalds 	default:
8851da177e4SLinus Torvalds 		result = -EINVAL;
8861da177e4SLinus Torvalds 		break;
8871da177e4SLinus Torvalds 	}
8881da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
8891da177e4SLinus Torvalds 	return result;
8901da177e4SLinus Torvalds }
8911da177e4SLinus Torvalds 
8921da177e4SLinus Torvalds 
893eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *substream)
8941da177e4SLinus Torvalds {
895eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
896eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
897eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
8981da177e4SLinus Torvalds 	unsigned int ptr;
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds 	if (!epcm->running)
9011da177e4SLinus Torvalds 		return 0;
9021da177e4SLinus Torvalds 	if (epcm->first_ptr) {
9039f4bd5ddSJames Courtier-Dutton 		udelay(50);	/* hack, it takes awhile until capture is started */
9041da177e4SLinus Torvalds 		epcm->first_ptr = 0;
9051da177e4SLinus Torvalds 	}
9061da177e4SLinus Torvalds 	ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff;
9071da177e4SLinus Torvalds 	return bytes_to_frames(runtime, ptr);
9081da177e4SLinus Torvalds }
9091da177e4SLinus Torvalds 
9101da177e4SLinus Torvalds /*
9111da177e4SLinus Torvalds  *  Playback support device description
9121da177e4SLinus Torvalds  */
9131da177e4SLinus Torvalds 
9147c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_playback =
9151da177e4SLinus Torvalds {
9161da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
9171da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
91809668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
9191da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
9201da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
9211da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000,
9221da177e4SLinus Torvalds 	.rate_min =		4000,
9231da177e4SLinus Torvalds 	.rate_max =		96000,
9241da177e4SLinus Torvalds 	.channels_min =		1,
9251da177e4SLinus Torvalds 	.channels_max =		2,
9261da177e4SLinus Torvalds 	.buffer_bytes_max =	(128*1024),
9271da177e4SLinus Torvalds 	.period_bytes_max =	(128*1024),
9281da177e4SLinus Torvalds 	.periods_min =		1,
9291da177e4SLinus Torvalds 	.periods_max =		1024,
9301da177e4SLinus Torvalds 	.fifo_size =		0,
9311da177e4SLinus Torvalds };
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds /*
9341da177e4SLinus Torvalds  *  Capture support device description
9351da177e4SLinus Torvalds  */
9361da177e4SLinus Torvalds 
9377c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_capture =
9381da177e4SLinus Torvalds {
9391da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
9401da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
94109668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
9421da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID),
9431da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
9441da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_8000_48000,
9451da177e4SLinus Torvalds 	.rate_min =		8000,
9461da177e4SLinus Torvalds 	.rate_max =		48000,
9471da177e4SLinus Torvalds 	.channels_min =		1,
9481da177e4SLinus Torvalds 	.channels_max =		2,
9491da177e4SLinus Torvalds 	.buffer_bytes_max =	(64*1024),
9501da177e4SLinus Torvalds 	.period_bytes_min =	384,
9511da177e4SLinus Torvalds 	.period_bytes_max =	(64*1024),
9521da177e4SLinus Torvalds 	.periods_min =		2,
9531da177e4SLinus Torvalds 	.periods_max =		2,
9541da177e4SLinus Torvalds 	.fifo_size =		0,
9551da177e4SLinus Torvalds };
9561da177e4SLinus Torvalds 
9577c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_capture_efx =
9589f4bd5ddSJames Courtier-Dutton {
9599f4bd5ddSJames Courtier-Dutton 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
9609f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
9619f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_INFO_RESUME |
9629f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_INFO_MMAP_VALID),
9639f4bd5ddSJames Courtier-Dutton 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
9649f4bd5ddSJames Courtier-Dutton 	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
9659f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
9669f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
9679f4bd5ddSJames Courtier-Dutton 	.rate_min =		44100,
9689f4bd5ddSJames Courtier-Dutton 	.rate_max =		192000,
9699f4bd5ddSJames Courtier-Dutton 	.channels_min =		8,
9709f4bd5ddSJames Courtier-Dutton 	.channels_max =		8,
9719f4bd5ddSJames Courtier-Dutton 	.buffer_bytes_max =	(64*1024),
9729f4bd5ddSJames Courtier-Dutton 	.period_bytes_min =	384,
9739f4bd5ddSJames Courtier-Dutton 	.period_bytes_max =	(64*1024),
9749f4bd5ddSJames Courtier-Dutton 	.periods_min =		2,
9759f4bd5ddSJames Courtier-Dutton 	.periods_max =		2,
9769f4bd5ddSJames Courtier-Dutton 	.fifo_size =		0,
9779f4bd5ddSJames Courtier-Dutton };
9789f4bd5ddSJames Courtier-Dutton 
9791da177e4SLinus Torvalds /*
9801da177e4SLinus Torvalds  *
9811da177e4SLinus Torvalds  */
9821da177e4SLinus Torvalds 
983eb4698f3STakashi Iwai static void snd_emu10k1_pcm_mixer_notify1(struct snd_emu10k1 *emu, struct snd_kcontrol *kctl, int idx, int activate)
9841da177e4SLinus Torvalds {
985eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
9861da177e4SLinus Torvalds 
9877c22f1aaSTakashi Iwai 	if (! kctl)
9887c22f1aaSTakashi Iwai 		return;
9891da177e4SLinus Torvalds 	if (activate)
9901da177e4SLinus Torvalds 		kctl->vd[idx].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
9911da177e4SLinus Torvalds 	else
9921da177e4SLinus Torvalds 		kctl->vd[idx].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
9931da177e4SLinus Torvalds 	snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
9941da177e4SLinus Torvalds 		       SNDRV_CTL_EVENT_MASK_INFO,
9951da177e4SLinus Torvalds 		       snd_ctl_build_ioff(&id, kctl, idx));
9961da177e4SLinus Torvalds }
9971da177e4SLinus Torvalds 
998eb4698f3STakashi Iwai static void snd_emu10k1_pcm_mixer_notify(struct snd_emu10k1 *emu, int idx, int activate)
9991da177e4SLinus Torvalds {
10001da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_routing, idx, activate);
10011da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_volume, idx, activate);
10021da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_attn, idx, activate);
10031da177e4SLinus Torvalds }
10041da177e4SLinus Torvalds 
1005eb4698f3STakashi Iwai static void snd_emu10k1_pcm_efx_mixer_notify(struct snd_emu10k1 *emu, int idx, int activate)
10061da177e4SLinus Torvalds {
10071da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_routing, idx, activate);
10081da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_volume, idx, activate);
10091da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_attn, idx, activate);
10101da177e4SLinus Torvalds }
10111da177e4SLinus Torvalds 
1012eb4698f3STakashi Iwai static void snd_emu10k1_pcm_free_substream(struct snd_pcm_runtime *runtime)
10131da177e4SLinus Torvalds {
10144d572776SJesper Juhl 	kfree(runtime->private_data);
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds 
1017eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream)
10181da177e4SLinus Torvalds {
1019eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1020eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
10211da177e4SLinus Torvalds 	int i;
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
10241da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[i];
10251da177e4SLinus Torvalds 		mix->epcm = NULL;
10261da177e4SLinus Torvalds 		snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0);
10271da177e4SLinus Torvalds 	}
10281da177e4SLinus Torvalds 	return 0;
10291da177e4SLinus Torvalds }
10301da177e4SLinus Torvalds 
10310be0a62fSOswald Buddenhagen static int snd_emu10k1_playback_set_constraints(struct snd_pcm_runtime *runtime)
10320be0a62fSOswald Buddenhagen {
10330be0a62fSOswald Buddenhagen 	int err;
10340be0a62fSOswald Buddenhagen 
10350be0a62fSOswald Buddenhagen 	// The buffer size must be a multiple of the period size, to avoid a
10360be0a62fSOswald Buddenhagen 	// mismatch between the extra voice and the regular voices.
10370be0a62fSOswald Buddenhagen 	err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
10380be0a62fSOswald Buddenhagen 	if (err < 0)
10390be0a62fSOswald Buddenhagen 		return err;
10400be0a62fSOswald Buddenhagen 	// The hardware is typically the cache's size of 64 frames ahead.
10410be0a62fSOswald Buddenhagen 	// Leave enough time for actually filling up the buffer.
10420be0a62fSOswald Buddenhagen 	err = snd_pcm_hw_constraint_minmax(
10430be0a62fSOswald Buddenhagen 			runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 128, UINT_MAX);
10440be0a62fSOswald Buddenhagen 	return err;
10450be0a62fSOswald Buddenhagen }
10460be0a62fSOswald Buddenhagen 
1047eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream)
10481da177e4SLinus Torvalds {
1049eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1050eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1051eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
1052eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
10530be0a62fSOswald Buddenhagen 	int i, j, err;
10541da177e4SLinus Torvalds 
1055e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
10561da177e4SLinus Torvalds 	if (epcm == NULL)
10571da177e4SLinus Torvalds 		return -ENOMEM;
10581da177e4SLinus Torvalds 	epcm->emu = emu;
10591da177e4SLinus Torvalds 	epcm->type = PLAYBACK_EFX;
10601da177e4SLinus Torvalds 	epcm->substream = substream;
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 	runtime->private_data = epcm;
10631da177e4SLinus Torvalds 	runtime->private_free = snd_emu10k1_pcm_free_substream;
10641da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_efx_playback;
10650be0a62fSOswald Buddenhagen 	err = snd_emu10k1_playback_set_constraints(runtime);
10660be0a62fSOswald Buddenhagen 	if (err < 0) {
10670be0a62fSOswald Buddenhagen 		kfree(epcm);
10680be0a62fSOswald Buddenhagen 		return err;
10690be0a62fSOswald Buddenhagen 	}
10701da177e4SLinus Torvalds 
10711da177e4SLinus Torvalds 	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
10721da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[i];
1073155e3d3bSOswald Buddenhagen 		for (j = 0; j < 8; j++)
1074155e3d3bSOswald Buddenhagen 			mix->send_routing[0][j] = i + j;
10751da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
10761da177e4SLinus Torvalds 		mix->send_volume[0][0] = 255;
1077bcdbd3b7SOswald Buddenhagen 		mix->attn[0] = 0x8000;
10781da177e4SLinus Torvalds 		mix->epcm = epcm;
10791da177e4SLinus Torvalds 		snd_emu10k1_pcm_efx_mixer_notify(emu, i, 1);
10801da177e4SLinus Torvalds 	}
10811da177e4SLinus Torvalds 	return 0;
10821da177e4SLinus Torvalds }
10831da177e4SLinus Torvalds 
1084eb4698f3STakashi Iwai static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
10851da177e4SLinus Torvalds {
1086eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1087eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1088eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
1089eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1090d0ec95feSMihail Zenkov 	int i, err, sample_rate;
10911da177e4SLinus Torvalds 
1092e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
10931da177e4SLinus Torvalds 	if (epcm == NULL)
10941da177e4SLinus Torvalds 		return -ENOMEM;
10951da177e4SLinus Torvalds 	epcm->emu = emu;
10961da177e4SLinus Torvalds 	epcm->type = PLAYBACK_EMUVOICE;
10971da177e4SLinus Torvalds 	epcm->substream = substream;
10981da177e4SLinus Torvalds 	runtime->private_data = epcm;
10991da177e4SLinus Torvalds 	runtime->private_free = snd_emu10k1_pcm_free_substream;
11001da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_playback;
11010be0a62fSOswald Buddenhagen 	err = snd_emu10k1_playback_set_constraints(runtime);
110212bda107STakashi Iwai 	if (err < 0) {
11031da177e4SLinus Torvalds 		kfree(epcm);
11041da177e4SLinus Torvalds 		return err;
11051da177e4SLinus Torvalds 	}
1106d0ec95feSMihail Zenkov 	if (emu->card_capabilities->emu_model && emu->emu1010.internal_clock == 0)
1107d0ec95feSMihail Zenkov 		sample_rate = 44100;
1108d0ec95feSMihail Zenkov 	else
1109d0ec95feSMihail Zenkov 		sample_rate = 48000;
1110d0ec95feSMihail Zenkov 	err = snd_pcm_hw_rule_noresample(runtime, sample_rate);
111157e5c630SClemens Ladisch 	if (err < 0) {
111257e5c630SClemens Ladisch 		kfree(epcm);
111357e5c630SClemens Ladisch 		return err;
111457e5c630SClemens Ladisch 	}
11151da177e4SLinus Torvalds 	mix = &emu->pcm_mixer[substream->number];
1116155e3d3bSOswald Buddenhagen 	for (i = 0; i < 8; i++)
11171da177e4SLinus Torvalds 		mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i;
11181da177e4SLinus Torvalds 	memset(&mix->send_volume, 0, sizeof(mix->send_volume));
11191da177e4SLinus Torvalds 	mix->send_volume[0][0] = mix->send_volume[0][1] =
11201da177e4SLinus Torvalds 	mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
1121bcdbd3b7SOswald Buddenhagen 	mix->attn[0] = mix->attn[1] = mix->attn[2] = 0x8000;
11221da177e4SLinus Torvalds 	mix->epcm = epcm;
11231da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1);
11241da177e4SLinus Torvalds 	return 0;
11251da177e4SLinus Torvalds }
11261da177e4SLinus Torvalds 
1127eb4698f3STakashi Iwai static int snd_emu10k1_playback_close(struct snd_pcm_substream *substream)
11281da177e4SLinus Torvalds {
1129eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1130eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[substream->number];
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds 	mix->epcm = NULL;
11331da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify(emu, substream->number, 0);
11341da177e4SLinus Torvalds 	return 0;
11351da177e4SLinus Torvalds }
11361da177e4SLinus Torvalds 
1137eb4698f3STakashi Iwai static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream)
11381da177e4SLinus Torvalds {
1139eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1140eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1141eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
11421da177e4SLinus Torvalds 
1143e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
11441da177e4SLinus Torvalds 	if (epcm == NULL)
11451da177e4SLinus Torvalds 		return -ENOMEM;
11461da177e4SLinus Torvalds 	epcm->emu = emu;
11471da177e4SLinus Torvalds 	epcm->type = CAPTURE_AC97ADC;
11481da177e4SLinus Torvalds 	epcm->substream = substream;
11491da177e4SLinus Torvalds 	epcm->capture_ipr = IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL;
11501da177e4SLinus Torvalds 	epcm->capture_inte = INTE_ADCBUFENABLE;
11511da177e4SLinus Torvalds 	epcm->capture_ba_reg = ADCBA;
11521da177e4SLinus Torvalds 	epcm->capture_bs_reg = ADCBS;
11531da177e4SLinus Torvalds 	epcm->capture_idx_reg = emu->audigy ? A_ADCIDX : ADCIDX;
11541da177e4SLinus Torvalds 	runtime->private_data = epcm;
11551da177e4SLinus Torvalds 	runtime->private_free = snd_emu10k1_pcm_free_substream;
11561da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_capture;
11571da177e4SLinus Torvalds 	emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt;
11581da177e4SLinus Torvalds 	emu->pcm_capture_substream = substream;
11591da177e4SLinus Torvalds 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes);
11601da177e4SLinus Torvalds 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates);
11611da177e4SLinus Torvalds 	return 0;
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds 
1164eb4698f3STakashi Iwai static int snd_emu10k1_capture_close(struct snd_pcm_substream *substream)
11651da177e4SLinus Torvalds {
1166eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 	emu->capture_interrupt = NULL;
11691da177e4SLinus Torvalds 	emu->pcm_capture_substream = NULL;
11701da177e4SLinus Torvalds 	return 0;
11711da177e4SLinus Torvalds }
11721da177e4SLinus Torvalds 
1173eb4698f3STakashi Iwai static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream)
11741da177e4SLinus Torvalds {
1175eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1176eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1177eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
11781da177e4SLinus Torvalds 
1179e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
11801da177e4SLinus Torvalds 	if (epcm == NULL)
11811da177e4SLinus Torvalds 		return -ENOMEM;
11821da177e4SLinus Torvalds 	epcm->emu = emu;
11831da177e4SLinus Torvalds 	epcm->type = CAPTURE_AC97MIC;
11841da177e4SLinus Torvalds 	epcm->substream = substream;
11851da177e4SLinus Torvalds 	epcm->capture_ipr = IPR_MICBUFFULL|IPR_MICBUFHALFFULL;
11861da177e4SLinus Torvalds 	epcm->capture_inte = INTE_MICBUFENABLE;
11871da177e4SLinus Torvalds 	epcm->capture_ba_reg = MICBA;
11881da177e4SLinus Torvalds 	epcm->capture_bs_reg = MICBS;
11891da177e4SLinus Torvalds 	epcm->capture_idx_reg = emu->audigy ? A_MICIDX : MICIDX;
11901da177e4SLinus Torvalds 	substream->runtime->private_data = epcm;
11911da177e4SLinus Torvalds 	substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
11921da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_capture;
11931da177e4SLinus Torvalds 	runtime->hw.rates = SNDRV_PCM_RATE_8000;
11941da177e4SLinus Torvalds 	runtime->hw.rate_min = runtime->hw.rate_max = 8000;
11951da177e4SLinus Torvalds 	runtime->hw.channels_min = 1;
11961da177e4SLinus Torvalds 	emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt;
11971da177e4SLinus Torvalds 	emu->pcm_capture_mic_substream = substream;
11981da177e4SLinus Torvalds 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes);
11991da177e4SLinus Torvalds 	return 0;
12001da177e4SLinus Torvalds }
12011da177e4SLinus Torvalds 
1202eb4698f3STakashi Iwai static int snd_emu10k1_capture_mic_close(struct snd_pcm_substream *substream)
12031da177e4SLinus Torvalds {
1204eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
12051da177e4SLinus Torvalds 
1206b09c551cSOswald Buddenhagen 	emu->capture_mic_interrupt = NULL;
12071da177e4SLinus Torvalds 	emu->pcm_capture_mic_substream = NULL;
12081da177e4SLinus Torvalds 	return 0;
12091da177e4SLinus Torvalds }
12101da177e4SLinus Torvalds 
1211eb4698f3STakashi Iwai static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
12121da177e4SLinus Torvalds {
1213eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1214eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1215eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
12161da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
12171da177e4SLinus Torvalds 	int idx;
12181da177e4SLinus Torvalds 
1219e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
12201da177e4SLinus Torvalds 	if (epcm == NULL)
12211da177e4SLinus Torvalds 		return -ENOMEM;
12221da177e4SLinus Torvalds 	epcm->emu = emu;
12231da177e4SLinus Torvalds 	epcm->type = CAPTURE_EFX;
12241da177e4SLinus Torvalds 	epcm->substream = substream;
12251da177e4SLinus Torvalds 	epcm->capture_ipr = IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL;
12261da177e4SLinus Torvalds 	epcm->capture_inte = INTE_EFXBUFENABLE;
12271da177e4SLinus Torvalds 	epcm->capture_ba_reg = FXBA;
12281da177e4SLinus Torvalds 	epcm->capture_bs_reg = FXBS;
12291da177e4SLinus Torvalds 	epcm->capture_idx_reg = FXIDX;
12301da177e4SLinus Torvalds 	substream->runtime->private_data = epcm;
12311da177e4SLinus Torvalds 	substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
12329f4bd5ddSJames Courtier-Dutton 	runtime->hw = snd_emu10k1_capture_efx;
12331da177e4SLinus Torvalds 	runtime->hw.rates = SNDRV_PCM_RATE_48000;
12341da177e4SLinus Torvalds 	runtime->hw.rate_min = runtime->hw.rate_max = 48000;
12351da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
1236190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
12379f4bd5ddSJames Courtier-Dutton 		/* TODO
12389f4bd5ddSJames Courtier-Dutton 		 * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
12399f4bd5ddSJames Courtier-Dutton 		 * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
12409f4bd5ddSJames Courtier-Dutton 		 * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
12419f4bd5ddSJames Courtier-Dutton 		 * rate_min = 44100,
12429f4bd5ddSJames Courtier-Dutton 		 * rate_max = 192000,
124313d45709SPavel Hofman 		 * channels_min = 16,
124413d45709SPavel Hofman 		 * channels_max = 16,
12459f4bd5ddSJames Courtier-Dutton 		 * Need to add mixer control to fix sample rate
12469f4bd5ddSJames Courtier-Dutton 		 *
124713d45709SPavel Hofman 		 * There are 32 mono channels of 16bits each.
1248a869057cSOswald Buddenhagen 		 * 24bit Audio uses 2x channels over 16bit,
1249a869057cSOswald Buddenhagen 		 * 96kHz uses 2x channels over 48kHz,
1250a869057cSOswald Buddenhagen 		 * 192kHz uses 4x channels over 48kHz.
1251a869057cSOswald Buddenhagen 		 * So, for 48kHz 24bit, one has 16 channels,
1252a869057cSOswald Buddenhagen 		 * for 96kHz 24bit, one has 8 channels,
1253a869057cSOswald Buddenhagen 		 * for 192kHz 24bit, one has 4 channels.
1254a869057cSOswald Buddenhagen 		 * 1010rev2 and 1616(m) cards have double that,
1255a869057cSOswald Buddenhagen 		 * but we don't exceed 16 channels anyway.
12569f4bd5ddSJames Courtier-Dutton 		 */
12579f4bd5ddSJames Courtier-Dutton #if 1
1258b0dbdaeaSJames Courtier-Dutton 		switch (emu->emu1010.internal_clock) {
1259b0dbdaeaSJames Courtier-Dutton 		case 0:
1260b0dbdaeaSJames Courtier-Dutton 			/* For 44.1kHz */
1261b0dbdaeaSJames Courtier-Dutton 			runtime->hw.rates = SNDRV_PCM_RATE_44100;
1262b0dbdaeaSJames Courtier-Dutton 			runtime->hw.rate_min = runtime->hw.rate_max = 44100;
126313d45709SPavel Hofman 			runtime->hw.channels_min =
126413d45709SPavel Hofman 				runtime->hw.channels_max = 16;
1265b0dbdaeaSJames Courtier-Dutton 			break;
1266b0dbdaeaSJames Courtier-Dutton 		case 1:
12679f4bd5ddSJames Courtier-Dutton 			/* For 48kHz */
12689f4bd5ddSJames Courtier-Dutton 			runtime->hw.rates = SNDRV_PCM_RATE_48000;
12699f4bd5ddSJames Courtier-Dutton 			runtime->hw.rate_min = runtime->hw.rate_max = 48000;
127013d45709SPavel Hofman 			runtime->hw.channels_min =
127113d45709SPavel Hofman 				runtime->hw.channels_max = 16;
1272b0dbdaeaSJames Courtier-Dutton 			break;
1273395d9dd5SPeter Senna Tschudin 		}
12749f4bd5ddSJames Courtier-Dutton #endif
12759f4bd5ddSJames Courtier-Dutton #if 0
12769f4bd5ddSJames Courtier-Dutton 		/* For 96kHz */
12779f4bd5ddSJames Courtier-Dutton 		runtime->hw.rates = SNDRV_PCM_RATE_96000;
12789f4bd5ddSJames Courtier-Dutton 		runtime->hw.rate_min = runtime->hw.rate_max = 96000;
12799f4bd5ddSJames Courtier-Dutton 		runtime->hw.channels_min = runtime->hw.channels_max = 4;
12809f4bd5ddSJames Courtier-Dutton #endif
12819f4bd5ddSJames Courtier-Dutton #if 0
12829f4bd5ddSJames Courtier-Dutton 		/* For 192kHz */
12839f4bd5ddSJames Courtier-Dutton 		runtime->hw.rates = SNDRV_PCM_RATE_192000;
12849f4bd5ddSJames Courtier-Dutton 		runtime->hw.rate_min = runtime->hw.rate_max = 192000;
12859f4bd5ddSJames Courtier-Dutton 		runtime->hw.channels_min = runtime->hw.channels_max = 2;
12869f4bd5ddSJames Courtier-Dutton #endif
12879f4bd5ddSJames Courtier-Dutton 		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
12889f4bd5ddSJames Courtier-Dutton 		/* efx_voices_mask[0] is expected to be zero
128913d45709SPavel Hofman  		 * efx_voices_mask[1] is expected to have 32bits set
12909f4bd5ddSJames Courtier-Dutton 		 */
12919f4bd5ddSJames Courtier-Dutton 	} else {
12921da177e4SLinus Torvalds 		runtime->hw.channels_min = runtime->hw.channels_max = 0;
12931da177e4SLinus Torvalds 		for (idx = 0; idx < nefx; idx++) {
12941da177e4SLinus Torvalds 			if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
12951da177e4SLinus Torvalds 				runtime->hw.channels_min++;
12961da177e4SLinus Torvalds 				runtime->hw.channels_max++;
12971da177e4SLinus Torvalds 			}
12981da177e4SLinus Torvalds 		}
12999f4bd5ddSJames Courtier-Dutton 	}
13001da177e4SLinus Torvalds 	epcm->capture_cr_val = emu->efx_voices_mask[0];
13011da177e4SLinus Torvalds 	epcm->capture_cr_val2 = emu->efx_voices_mask[1];
13021da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
13031da177e4SLinus Torvalds 	emu->capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt;
13041da177e4SLinus Torvalds 	emu->pcm_capture_efx_substream = substream;
13051da177e4SLinus Torvalds 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes);
13061da177e4SLinus Torvalds 	return 0;
13071da177e4SLinus Torvalds }
13081da177e4SLinus Torvalds 
1309eb4698f3STakashi Iwai static int snd_emu10k1_capture_efx_close(struct snd_pcm_substream *substream)
13101da177e4SLinus Torvalds {
1311eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
13121da177e4SLinus Torvalds 
1313b09c551cSOswald Buddenhagen 	emu->capture_efx_interrupt = NULL;
13141da177e4SLinus Torvalds 	emu->pcm_capture_efx_substream = NULL;
13151da177e4SLinus Torvalds 	return 0;
13161da177e4SLinus Torvalds }
13171da177e4SLinus Torvalds 
13186769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_playback_ops = {
13191da177e4SLinus Torvalds 	.open =			snd_emu10k1_playback_open,
13201da177e4SLinus Torvalds 	.close =		snd_emu10k1_playback_close,
13211da177e4SLinus Torvalds 	.hw_params =		snd_emu10k1_playback_hw_params,
13221da177e4SLinus Torvalds 	.hw_free =		snd_emu10k1_playback_hw_free,
13231da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_playback_prepare,
13241da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_playback_trigger,
13251da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_playback_pointer,
13261da177e4SLinus Torvalds };
13271da177e4SLinus Torvalds 
13286769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_capture_ops = {
13291da177e4SLinus Torvalds 	.open =			snd_emu10k1_capture_open,
13301da177e4SLinus Torvalds 	.close =		snd_emu10k1_capture_close,
13311da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_capture_prepare,
13321da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_capture_trigger,
13331da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_capture_pointer,
13341da177e4SLinus Torvalds };
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds /* EFX playback */
13376769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
13381da177e4SLinus Torvalds 	.open =			snd_emu10k1_efx_playback_open,
13391da177e4SLinus Torvalds 	.close =		snd_emu10k1_efx_playback_close,
13401da177e4SLinus Torvalds 	.hw_params =		snd_emu10k1_playback_hw_params,
134179852438SOswald Buddenhagen 	.hw_free =		snd_emu10k1_playback_hw_free,
13421da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_efx_playback_prepare,
13431da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_efx_playback_trigger,
1344b9468c41SOswald Buddenhagen 	.pointer =		snd_emu10k1_playback_pointer,
13451da177e4SLinus Torvalds };
13461da177e4SLinus Torvalds 
1347bb814c39SLars-Peter Clausen int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
13481da177e4SLinus Torvalds {
1349eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
1350eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream;
13511da177e4SLinus Torvalds 	int err;
13521da177e4SLinus Torvalds 
135312bda107STakashi Iwai 	err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm);
135412bda107STakashi Iwai 	if (err < 0)
13551da177e4SLinus Torvalds 		return err;
13561da177e4SLinus Torvalds 
13571da177e4SLinus Torvalds 	pcm->private_data = emu;
13581da177e4SLinus Torvalds 
13591da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_playback_ops);
13601da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_ops);
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 	pcm->info_flags = 0;
13631da177e4SLinus Torvalds 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
13641da177e4SLinus Torvalds 	strcpy(pcm->name, "ADC Capture/Standard PCM Playback");
13651da177e4SLinus Torvalds 	emu->pcm = pcm;
13661da177e4SLinus Torvalds 
1367cbf7dcd9STakashi Iwai 	/* playback substream can't use managed buffers due to alignment */
13681da177e4SLinus Torvalds 	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
13695116b94aSTakashi Iwai 		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG,
13706974f8adSTakashi Iwai 					      &emu->pci->dev,
13715116b94aSTakashi Iwai 					      64*1024, 64*1024);
13721da177e4SLinus Torvalds 
13731da177e4SLinus Torvalds 	for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
1374cbf7dcd9STakashi Iwai 		snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV,
1375cbf7dcd9STakashi Iwai 					   &emu->pci->dev, 64*1024, 64*1024);
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds 	return 0;
13781da177e4SLinus Torvalds }
13791da177e4SLinus Torvalds 
1380bb814c39SLars-Peter Clausen int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device)
13811da177e4SLinus Torvalds {
1382eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
1383eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream;
13841da177e4SLinus Torvalds 	int err;
13851da177e4SLinus Torvalds 
138612bda107STakashi Iwai 	err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm);
138712bda107STakashi Iwai 	if (err < 0)
13881da177e4SLinus Torvalds 		return err;
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 	pcm->private_data = emu;
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_efx_playback_ops);
13931da177e4SLinus Torvalds 
13941da177e4SLinus Torvalds 	pcm->info_flags = 0;
13951da177e4SLinus Torvalds 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
13961da177e4SLinus Torvalds 	strcpy(pcm->name, "Multichannel Playback");
139709668b44STakashi Iwai 	emu->pcm_multi = pcm;
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds 	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
14005116b94aSTakashi Iwai 		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG,
14016974f8adSTakashi Iwai 					      &emu->pci->dev,
14025116b94aSTakashi Iwai 					      64*1024, 64*1024);
14031da177e4SLinus Torvalds 
14041da177e4SLinus Torvalds 	return 0;
14051da177e4SLinus Torvalds }
14061da177e4SLinus Torvalds 
14071da177e4SLinus Torvalds 
14086769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_capture_mic_ops = {
14091da177e4SLinus Torvalds 	.open =			snd_emu10k1_capture_mic_open,
14101da177e4SLinus Torvalds 	.close =		snd_emu10k1_capture_mic_close,
14111da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_capture_prepare,
14121da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_capture_trigger,
14131da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_capture_pointer,
14141da177e4SLinus Torvalds };
14151da177e4SLinus Torvalds 
1416bb814c39SLars-Peter Clausen int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device)
14171da177e4SLinus Torvalds {
1418eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
14191da177e4SLinus Torvalds 	int err;
14201da177e4SLinus Torvalds 
142112bda107STakashi Iwai 	err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm);
142212bda107STakashi Iwai 	if (err < 0)
14231da177e4SLinus Torvalds 		return err;
14241da177e4SLinus Torvalds 
14251da177e4SLinus Torvalds 	pcm->private_data = emu;
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops);
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds 	pcm->info_flags = 0;
14301da177e4SLinus Torvalds 	strcpy(pcm->name, "Mic Capture");
14311da177e4SLinus Torvalds 	emu->pcm_mic = pcm;
14321da177e4SLinus Torvalds 
1433cbf7dcd9STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
14345116b94aSTakashi Iwai 				       64*1024, 64*1024);
14351da177e4SLinus Torvalds 
14361da177e4SLinus Torvalds 	return 0;
14371da177e4SLinus Torvalds }
14381da177e4SLinus Torvalds 
1439eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14401da177e4SLinus Torvalds {
1441eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14421da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
14431da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
14441da177e4SLinus Torvalds 	uinfo->count = nefx;
14451da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14461da177e4SLinus Torvalds 	uinfo->value.integer.max = 1;
14471da177e4SLinus Torvalds 	return 0;
14481da177e4SLinus Torvalds }
14491da177e4SLinus Torvalds 
1450eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
14511da177e4SLinus Torvalds {
1452eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14531da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
14541da177e4SLinus Torvalds 	int idx;
14551da177e4SLinus Torvalds 
14561da177e4SLinus Torvalds 	for (idx = 0; idx < nefx; idx++)
14571da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0;
14581da177e4SLinus Torvalds 	return 0;
14591da177e4SLinus Torvalds }
14601da177e4SLinus Torvalds 
1461eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
14621da177e4SLinus Torvalds {
1463eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14641da177e4SLinus Torvalds 	unsigned int nval[2], bits;
14651da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
14661da177e4SLinus Torvalds 	int nefxb = emu->audigy ? 7 : 6;
14671da177e4SLinus Torvalds 	int change, idx;
14681da177e4SLinus Torvalds 
14691da177e4SLinus Torvalds 	nval[0] = nval[1] = 0;
14701da177e4SLinus Torvalds 	for (idx = 0, bits = 0; idx < nefx; idx++)
14711da177e4SLinus Torvalds 		if (ucontrol->value.integer.value[idx]) {
14721da177e4SLinus Torvalds 			nval[idx / 32] |= 1 << (idx % 32);
14731da177e4SLinus Torvalds 			bits++;
14741da177e4SLinus Torvalds 		}
14751da177e4SLinus Torvalds 
1476a869057cSOswald Buddenhagen 	// Check that the number of requested channels is a power of two
1477a869057cSOswald Buddenhagen 	// not bigger than the number of available channels.
14781da177e4SLinus Torvalds 	for (idx = 0; idx < nefxb; idx++)
14791da177e4SLinus Torvalds 		if (1 << idx == bits)
14801da177e4SLinus Torvalds 			break;
14811da177e4SLinus Torvalds 	if (idx >= nefxb)
14821da177e4SLinus Torvalds 		return -EINVAL;
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
14851da177e4SLinus Torvalds 	change = (nval[0] != emu->efx_voices_mask[0]) ||
14861da177e4SLinus Torvalds 		(nval[1] != emu->efx_voices_mask[1]);
14871da177e4SLinus Torvalds 	emu->efx_voices_mask[0] = nval[0];
14881da177e4SLinus Torvalds 	emu->efx_voices_mask[1] = nval[1];
14891da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
14901da177e4SLinus Torvalds 	return change;
14911da177e4SLinus Torvalds }
14921da177e4SLinus Torvalds 
1493f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = {
14941da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
14951da177e4SLinus Torvalds 	.name = "Captured FX8010 Outputs",
14961da177e4SLinus Torvalds 	.info = snd_emu10k1_pcm_efx_voices_mask_info,
14971da177e4SLinus Torvalds 	.get = snd_emu10k1_pcm_efx_voices_mask_get,
14981da177e4SLinus Torvalds 	.put = snd_emu10k1_pcm_efx_voices_mask_put
14991da177e4SLinus Torvalds };
15001da177e4SLinus Torvalds 
15016769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_capture_efx_ops = {
15021da177e4SLinus Torvalds 	.open =			snd_emu10k1_capture_efx_open,
15031da177e4SLinus Torvalds 	.close =		snd_emu10k1_capture_efx_close,
15041da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_capture_prepare,
15051da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_capture_trigger,
15061da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_capture_pointer,
15071da177e4SLinus Torvalds };
15081da177e4SLinus Torvalds 
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds /* EFX playback */
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds #define INITIAL_TRAM_SHIFT     14
15131da177e4SLinus Torvalds #define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1)
15141da177e4SLinus Torvalds 
1515eb4698f3STakashi Iwai static void snd_emu10k1_fx8010_playback_irq(struct snd_emu10k1 *emu, void *private_data)
15161da177e4SLinus Torvalds {
1517eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream = private_data;
15181da177e4SLinus Torvalds 	snd_pcm_period_elapsed(substream);
15191da177e4SLinus Torvalds }
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,
15221da177e4SLinus Torvalds 						   unsigned short *dst_right,
15231da177e4SLinus Torvalds 						   unsigned short *src,
15241da177e4SLinus Torvalds 						   unsigned int count,
15251da177e4SLinus Torvalds 						   unsigned int tram_shift)
15261da177e4SLinus Torvalds {
152728a97c19STakashi Iwai 	/*
15286f002b02STakashi Iwai 	dev_dbg(emu->card->dev,
15296f002b02STakashi Iwai 		"tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
153028a97c19STakashi Iwai 	       "src = 0x%p, count = 0x%x\n",
153128a97c19STakashi Iwai 	       dst_left, dst_right, src, count);
153228a97c19STakashi Iwai 	*/
15331da177e4SLinus Torvalds 	if ((tram_shift & 1) == 0) {
15341da177e4SLinus Torvalds 		while (count--) {
15351da177e4SLinus Torvalds 			*dst_left-- = *src++;
15361da177e4SLinus Torvalds 			*dst_right-- = *src++;
15371da177e4SLinus Torvalds 		}
15381da177e4SLinus Torvalds 	} else {
15391da177e4SLinus Torvalds 		while (count--) {
15401da177e4SLinus Torvalds 			*dst_right-- = *src++;
15411da177e4SLinus Torvalds 			*dst_left-- = *src++;
15421da177e4SLinus Torvalds 		}
15431da177e4SLinus Torvalds 	}
15441da177e4SLinus Torvalds }
15451da177e4SLinus Torvalds 
1546eb4698f3STakashi Iwai static void fx8010_pb_trans_copy(struct snd_pcm_substream *substream,
1547eb4698f3STakashi Iwai 				 struct snd_pcm_indirect *rec, size_t bytes)
15481da177e4SLinus Torvalds {
1549eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1550eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
15511da177e4SLinus Torvalds 	unsigned int tram_size = pcm->buffer_size;
15521da177e4SLinus Torvalds 	unsigned short *src = (unsigned short *)(substream->runtime->dma_area + rec->sw_data);
15531da177e4SLinus Torvalds 	unsigned int frames = bytes >> 2, count;
15541da177e4SLinus Torvalds 	unsigned int tram_pos = pcm->tram_pos;
15551da177e4SLinus Torvalds 	unsigned int tram_shift = pcm->tram_shift;
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 	while (frames > tram_pos) {
15581da177e4SLinus Torvalds 		count = tram_pos + 1;
15591da177e4SLinus Torvalds 		snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos,
15601da177e4SLinus Torvalds 						       (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2,
15611da177e4SLinus Torvalds 						       src, count, tram_shift);
15621da177e4SLinus Torvalds 		src += count * 2;
15631da177e4SLinus Torvalds 		frames -= count;
15641da177e4SLinus Torvalds 		tram_pos = (tram_size / 2) - 1;
15651da177e4SLinus Torvalds 		tram_shift++;
15661da177e4SLinus Torvalds 	}
15671da177e4SLinus Torvalds 	snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos,
15681da177e4SLinus Torvalds 					       (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2,
15691da177e4SLinus Torvalds 					       src, frames, tram_shift);
15701da177e4SLinus Torvalds 	tram_pos -= frames;
15711da177e4SLinus Torvalds 	pcm->tram_pos = tram_pos;
15721da177e4SLinus Torvalds 	pcm->tram_shift = tram_shift;
15731da177e4SLinus Torvalds }
15741da177e4SLinus Torvalds 
1575eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_transfer(struct snd_pcm_substream *substream)
15761da177e4SLinus Torvalds {
1577eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1578eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
15791da177e4SLinus Torvalds 
158000277e2bSTakashi Iwai 	return snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec,
158100277e2bSTakashi Iwai 						  fx8010_pb_trans_copy);
15821da177e4SLinus Torvalds }
15831da177e4SLinus Torvalds 
1584eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_hw_free(struct snd_pcm_substream *substream)
15851da177e4SLinus Torvalds {
1586eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1587eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
15881da177e4SLinus Torvalds 	unsigned int i;
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 	for (i = 0; i < pcm->channels; i++)
15911da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, 0);
15921da177e4SLinus Torvalds 	return 0;
15931da177e4SLinus Torvalds }
15941da177e4SLinus Torvalds 
1595eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substream)
15961da177e4SLinus Torvalds {
1597eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1598eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1599eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16001da177e4SLinus Torvalds 	unsigned int i;
16011da177e4SLinus Torvalds 
160228a97c19STakashi Iwai 	/*
16036f002b02STakashi Iwai 	dev_dbg(emu->card->dev, "prepare: etram_pages = 0x%p, dma_area = 0x%x, "
160428a97c19STakashi Iwai 	       "buffer_size = 0x%x (0x%x)\n",
160528a97c19STakashi Iwai 	       emu->fx8010.etram_pages, runtime->dma_area,
160628a97c19STakashi Iwai 	       runtime->buffer_size, runtime->buffer_size << 2);
160728a97c19STakashi Iwai 	*/
16081da177e4SLinus Torvalds 	memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec));
16091da177e4SLinus Torvalds 	pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */
16101da177e4SLinus Torvalds 	pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
16111da177e4SLinus Torvalds 	pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size);
16121da177e4SLinus Torvalds 	pcm->tram_shift = 0;
161346055699SOswald Buddenhagen 	snd_emu10k1_ptr_write_multiple(emu, 0,
161446055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_running, 0,	/* reset */
161546055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_trigger, 0,	/* reset */
161646055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_size, runtime->buffer_size,
161746055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_ptr, 0,	/* reset ptr number */
161846055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_count, runtime->period_size,
161946055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_tmpcount, runtime->period_size,
162046055699SOswald Buddenhagen 		REGLIST_END);
16211da177e4SLinus Torvalds 	for (i = 0; i < pcm->channels; i++)
16221da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels));
16231da177e4SLinus Torvalds 	return 0;
16241da177e4SLinus Torvalds }
16251da177e4SLinus Torvalds 
1626eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substream, int cmd)
16271da177e4SLinus Torvalds {
1628eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1629eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16301da177e4SLinus Torvalds 	int result = 0;
16311da177e4SLinus Torvalds 
16321da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
16331da177e4SLinus Torvalds 	switch (cmd) {
16341da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
16351da177e4SLinus Torvalds 		/* follow thru */
16361da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
163709668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
16381da177e4SLinus Torvalds #ifdef EMU10K1_SET_AC3_IEC958
16391da177e4SLinus Torvalds 	{
16401da177e4SLinus Torvalds 		int i;
16411da177e4SLinus Torvalds 		for (i = 0; i < 3; i++) {
16421da177e4SLinus Torvalds 			unsigned int bits;
16431da177e4SLinus Torvalds 			bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
16441da177e4SLinus Torvalds 			       SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS |
16451da177e4SLinus Torvalds 			       0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA;
16461da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, SPCS0 + i, 0, bits);
16471da177e4SLinus Torvalds 		}
16481da177e4SLinus Torvalds 	}
16491da177e4SLinus Torvalds #endif
16501da177e4SLinus Torvalds 		result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq);
16511da177e4SLinus Torvalds 		if (result < 0)
16521da177e4SLinus Torvalds 			goto __err;
16531da177e4SLinus Torvalds 		snd_emu10k1_fx8010_playback_transfer(substream);	/* roll the ball */
16541da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1);
16551da177e4SLinus Torvalds 		break;
16561da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
16571da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
165809668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
1659057666b6STakashi Iwai 		snd_emu10k1_fx8010_unregister_irq_handler(emu, &pcm->irq);
16601da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0);
16611da177e4SLinus Torvalds 		pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size);
16621da177e4SLinus Torvalds 		pcm->tram_shift = 0;
16631da177e4SLinus Torvalds 		break;
16641da177e4SLinus Torvalds 	default:
16651da177e4SLinus Torvalds 		result = -EINVAL;
16661da177e4SLinus Torvalds 		break;
16671da177e4SLinus Torvalds 	}
16681da177e4SLinus Torvalds       __err:
16691da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
16701da177e4SLinus Torvalds 	return result;
16711da177e4SLinus Torvalds }
16721da177e4SLinus Torvalds 
1673eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(struct snd_pcm_substream *substream)
16741da177e4SLinus Torvalds {
1675eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1676eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16771da177e4SLinus Torvalds 	size_t ptr; /* byte pointer */
16781da177e4SLinus Torvalds 
16791da177e4SLinus Torvalds 	if (!snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_trigger, 0))
16801da177e4SLinus Torvalds 		return 0;
16811da177e4SLinus Torvalds 	ptr = snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_ptr, 0) << 2;
16821da177e4SLinus Torvalds 	return snd_pcm_indirect_playback_pointer(substream, &pcm->pcm_rec, ptr);
16831da177e4SLinus Torvalds }
16841da177e4SLinus Torvalds 
16857c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_fx8010_playback =
16861da177e4SLinus Torvalds {
16871da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
168809668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
168910a23f61STakashi Iwai 				 /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE |
169010a23f61STakashi Iwai 				 SNDRV_PCM_INFO_SYNC_APPLPTR),
16911da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
16921da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_48000,
16931da177e4SLinus Torvalds 	.rate_min =		48000,
16941da177e4SLinus Torvalds 	.rate_max =		48000,
16951da177e4SLinus Torvalds 	.channels_min =		1,
16961da177e4SLinus Torvalds 	.channels_max =		1,
16971da177e4SLinus Torvalds 	.buffer_bytes_max =	(128*1024),
16981da177e4SLinus Torvalds 	.period_bytes_min =	1024,
16991da177e4SLinus Torvalds 	.period_bytes_max =	(128*1024),
1700806d31d7STakashi Iwai 	.periods_min =		2,
17011da177e4SLinus Torvalds 	.periods_max =		1024,
17021da177e4SLinus Torvalds 	.fifo_size =		0,
17031da177e4SLinus Torvalds };
17041da177e4SLinus Torvalds 
1705eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_open(struct snd_pcm_substream *substream)
17061da177e4SLinus Torvalds {
1707eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1708eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1709eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
17101da177e4SLinus Torvalds 
17111da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_fx8010_playback;
17121da177e4SLinus Torvalds 	runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels;
17131da177e4SLinus Torvalds 	runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2;
17141da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
17151da177e4SLinus Torvalds 	if (pcm->valid == 0) {
17161da177e4SLinus Torvalds 		spin_unlock_irq(&emu->reg_lock);
17171da177e4SLinus Torvalds 		return -ENODEV;
17181da177e4SLinus Torvalds 	}
17191da177e4SLinus Torvalds 	pcm->opened = 1;
17201da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
17211da177e4SLinus Torvalds 	return 0;
17221da177e4SLinus Torvalds }
17231da177e4SLinus Torvalds 
1724eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_close(struct snd_pcm_substream *substream)
17251da177e4SLinus Torvalds {
1726eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1727eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
17281da177e4SLinus Torvalds 
17291da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
17301da177e4SLinus Torvalds 	pcm->opened = 0;
17311da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
17321da177e4SLinus Torvalds 	return 0;
17331da177e4SLinus Torvalds }
17341da177e4SLinus Torvalds 
17356769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = {
17361da177e4SLinus Torvalds 	.open =			snd_emu10k1_fx8010_playback_open,
17371da177e4SLinus Torvalds 	.close =		snd_emu10k1_fx8010_playback_close,
17381da177e4SLinus Torvalds 	.hw_free =		snd_emu10k1_fx8010_playback_hw_free,
17391da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_fx8010_playback_prepare,
17401da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_fx8010_playback_trigger,
17411da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_fx8010_playback_pointer,
17421da177e4SLinus Torvalds 	.ack =			snd_emu10k1_fx8010_playback_transfer,
17431da177e4SLinus Torvalds };
17441da177e4SLinus Torvalds 
1745bb814c39SLars-Peter Clausen int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
17461da177e4SLinus Torvalds {
1747eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
1748eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
17491da177e4SLinus Torvalds 	int err;
17501da177e4SLinus Torvalds 
17518dd13214SOswald Buddenhagen 	err = snd_pcm_new(emu->card, "emu10k1 efx", device, emu->audigy ? 0 : 8, 1, &pcm);
175212bda107STakashi Iwai 	if (err < 0)
17531da177e4SLinus Torvalds 		return err;
17541da177e4SLinus Torvalds 
17551da177e4SLinus Torvalds 	pcm->private_data = emu;
17561da177e4SLinus Torvalds 
17578dd13214SOswald Buddenhagen 	if (!emu->audigy)
17581da177e4SLinus Torvalds 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops);
17591da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops);
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds 	pcm->info_flags = 0;
17628dd13214SOswald Buddenhagen 	if (emu->audigy)
17638dd13214SOswald Buddenhagen 		strcpy(pcm->name, "Multichannel Capture");
17648dd13214SOswald Buddenhagen 	else
17651da177e4SLinus Torvalds 		strcpy(pcm->name, "Multichannel Capture/PT Playback");
17661da177e4SLinus Torvalds 	emu->pcm_efx = pcm;
17671da177e4SLinus Torvalds 
17681da177e4SLinus Torvalds 	/* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs
17691da177e4SLinus Torvalds 	 * to these
17701da177e4SLinus Torvalds 	 */
17711da177e4SLinus Torvalds 
17721da177e4SLinus Torvalds 	if (emu->audigy) {
17731da177e4SLinus Torvalds 		emu->efx_voices_mask[0] = 0;
1774190d2c46SJames Courtier-Dutton 		if (emu->card_capabilities->emu_model)
177513d45709SPavel Hofman 			/* Pavel Hofman - 32 voices will be used for
177613d45709SPavel Hofman 			 * capture (write mode) -
177713d45709SPavel Hofman 			 * each bit = corresponding voice
177813d45709SPavel Hofman 			 */
177913d45709SPavel Hofman 			emu->efx_voices_mask[1] = 0xffffffff;
178013d45709SPavel Hofman 		else
17811da177e4SLinus Torvalds 			emu->efx_voices_mask[1] = 0xffff;
17821da177e4SLinus Torvalds 	} else {
17831da177e4SLinus Torvalds 		emu->efx_voices_mask[0] = 0xffff0000;
17841da177e4SLinus Torvalds 		emu->efx_voices_mask[1] = 0;
17851da177e4SLinus Torvalds 	}
178613d45709SPavel Hofman 	/* For emu1010, the control has to set 32 upper bits (voices)
178713d45709SPavel Hofman 	 * out of the 64 bits (voices) to true for the 16-channels capture
178813d45709SPavel Hofman 	 * to work correctly. Correct A_FXWC2 initial value (0xffffffff)
178913d45709SPavel Hofman 	 * is already defined but the snd_emu10k1_pcm_efx_voices_mask
179013d45709SPavel Hofman 	 * control can override this register's value.
179113d45709SPavel Hofman 	 */
179267ed4161SClemens Ladisch 	kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
179367ed4161SClemens Ladisch 	if (!kctl)
179467ed4161SClemens Ladisch 		return -ENOMEM;
179567ed4161SClemens Ladisch 	kctl->id.device = device;
17966d531e7bSZhouyang Jia 	err = snd_ctl_add(emu->card, kctl);
17976d531e7bSZhouyang Jia 	if (err < 0)
17986d531e7bSZhouyang Jia 		return err;
17991da177e4SLinus Torvalds 
1800cbf7dcd9STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
18015116b94aSTakashi Iwai 				       64*1024, 64*1024);
18021da177e4SLinus Torvalds 
18031da177e4SLinus Torvalds 	return 0;
18041da177e4SLinus Torvalds }
1805