xref: /linux/sound/pci/emu10k1/emupcm.c (revision d2baa153c328efbbc3c4b939662e058b2cb544fd)
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 
125d2baa153SOswald Buddenhagen static const unsigned int capture_buffer_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 
136d2baa153SOswald Buddenhagen static const struct snd_pcm_hw_constraint_list hw_constraints_capture_buffer_sizes = {
1371da177e4SLinus Torvalds 	.count = 31,
138d2baa153SOswald Buddenhagen 	.list = capture_buffer_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;
4326dbecb9bSOswald Buddenhagen 	unsigned int extra_size, channel_size;
433f4ab5950SOswald Buddenhagen 	unsigned int i;
4341da177e4SLinus Torvalds 
435af7fd027SOswald Buddenhagen 	start_addr = epcm->start_addr >> 1;  // 16-bit voices
4361da177e4SLinus Torvalds 
4376dbecb9bSOswald Buddenhagen 	extra_size = runtime->period_size;
438af7fd027SOswald Buddenhagen 	channel_size = runtime->buffer_size;
4391da177e4SLinus Torvalds 
440f5192e33SOswald Buddenhagen 	snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, true,
4416dbecb9bSOswald Buddenhagen 					 start_addr, start_addr + extra_size);
4421da177e4SLinus Torvalds 
443fa75064dSOswald Buddenhagen 	epcm->ccca_start_addr = start_addr;
444f4ab5950SOswald Buddenhagen 	for (i = 0; i < runtime->channels; i++) {
4457195fb46SOswald Buddenhagen 		snd_emu10k1_pcm_init_voices(emu, epcm->voices[i], true, false,
4461da177e4SLinus Torvalds 					    start_addr, start_addr + channel_size,
4471da177e4SLinus Torvalds 					    &emu->efx_pcm_mixer[i]);
4481da177e4SLinus Torvalds 		start_addr += channel_size;
4491da177e4SLinus Torvalds 	}
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	return 0;
4521da177e4SLinus Torvalds }
4531da177e4SLinus Torvalds 
4547c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_efx_playback =
4551da177e4SLinus Torvalds {
4561da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED |
4571da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
45809668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
4591da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
4601da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
4611da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_48000,
4621da177e4SLinus Torvalds 	.rate_min =		48000,
4631da177e4SLinus Torvalds 	.rate_max =		48000,
464f4ab5950SOswald Buddenhagen 	.channels_min =		1,
4651da177e4SLinus Torvalds 	.channels_max =		NUM_EFX_PLAYBACK,
4660be0a62fSOswald Buddenhagen 	.buffer_bytes_max =	(128*1024),
4670be0a62fSOswald Buddenhagen 	.period_bytes_max =	(128*1024),
4681da177e4SLinus Torvalds 	.periods_min =		2,
4696dbecb9bSOswald Buddenhagen 	.periods_max =		1024,
4701da177e4SLinus Torvalds 	.fifo_size =		0,
4711da177e4SLinus Torvalds };
4721da177e4SLinus Torvalds 
473eb4698f3STakashi Iwai static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream)
4741da177e4SLinus Torvalds {
475eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
476eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
477eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
4781da177e4SLinus Torvalds 	int idx;
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	/* zeroing the buffer size will stop capture */
4811da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);
4821da177e4SLinus Torvalds 	switch (epcm->type) {
4831da177e4SLinus Torvalds 	case CAPTURE_AC97ADC:
4841da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);
4851da177e4SLinus Torvalds 		break;
4861da177e4SLinus Torvalds 	case CAPTURE_EFX:
4871da177e4SLinus Torvalds 		if (emu->audigy) {
48846055699SOswald Buddenhagen 			snd_emu10k1_ptr_write_multiple(emu, 0,
48946055699SOswald Buddenhagen 				A_FXWC1, 0,
49046055699SOswald Buddenhagen 				A_FXWC2, 0,
49146055699SOswald Buddenhagen 				REGLIST_END);
4921da177e4SLinus Torvalds 		} else
4931da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, FXWC, 0, 0);
4941da177e4SLinus Torvalds 		break;
4951da177e4SLinus Torvalds 	default:
4961da177e4SLinus Torvalds 		break;
4971da177e4SLinus Torvalds 	}
4981da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, epcm->capture_ba_reg, 0, runtime->dma_addr);
4991da177e4SLinus Torvalds 	epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream);
5001da177e4SLinus Torvalds 	epcm->capture_bs_val = 0;
5011da177e4SLinus Torvalds 	for (idx = 0; idx < 31; idx++) {
502d2baa153SOswald Buddenhagen 		if (capture_buffer_sizes[idx] == epcm->capture_bufsize) {
5031da177e4SLinus Torvalds 			epcm->capture_bs_val = idx + 1;
5041da177e4SLinus Torvalds 			break;
5051da177e4SLinus Torvalds 		}
5061da177e4SLinus Torvalds 	}
5071da177e4SLinus Torvalds 	if (epcm->capture_bs_val == 0) {
5081da177e4SLinus Torvalds 		snd_BUG();
5091da177e4SLinus Torvalds 		epcm->capture_bs_val++;
5101da177e4SLinus Torvalds 	}
5111da177e4SLinus Torvalds 	if (epcm->type == CAPTURE_AC97ADC) {
5121da177e4SLinus Torvalds 		epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
5131da177e4SLinus Torvalds 		if (runtime->channels > 1)
5141da177e4SLinus Torvalds 			epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
5151da177e4SLinus Torvalds 		epcm->capture_cr_val |= emu->audigy ?
5161da177e4SLinus Torvalds 			snd_emu10k1_audigy_capture_rate_reg(runtime->rate) :
5171da177e4SLinus Torvalds 			snd_emu10k1_capture_rate_reg(runtime->rate);
5181da177e4SLinus Torvalds 	}
5191da177e4SLinus Torvalds 	return 0;
5201da177e4SLinus Torvalds }
5211da177e4SLinus Torvalds 
5229581128aSOswald Buddenhagen static void snd_emu10k1_playback_fill_cache(struct snd_emu10k1 *emu,
5239581128aSOswald Buddenhagen 					    unsigned voice,
5249581128aSOswald Buddenhagen 					    u32 sample, bool stereo)
5251da177e4SLinus Torvalds {
5265b1cd21fSOswald Buddenhagen 	u32 ccr;
5271da177e4SLinus Torvalds 
5285b1cd21fSOswald Buddenhagen 	// We assume that the cache is resting at this point (i.e.,
5295b1cd21fSOswald Buddenhagen 	// CCR_CACHEINVALIDSIZE is very small).
5305b1cd21fSOswald Buddenhagen 
5315b1cd21fSOswald Buddenhagen 	// Clear leading frames. For simplicitly, this does too much,
5325b1cd21fSOswald Buddenhagen 	// except for 16-bit stereo. And the interpolator will actually
5335b1cd21fSOswald Buddenhagen 	// access them at all only when we're pitch-shifting.
5345b1cd21fSOswald Buddenhagen 	for (int i = 0; i < 3; i++)
5351da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample);
5365b1cd21fSOswald Buddenhagen 
5375b1cd21fSOswald Buddenhagen 	// Fill cache
5385b1cd21fSOswald Buddenhagen 	ccr = (64 - 3) << REG_SHIFT(CCR_CACHEINVALIDSIZE);
5391da177e4SLinus Torvalds 	if (stereo) {
5405b1cd21fSOswald Buddenhagen 		// The engine goes haywire if CCR_READADDRESS is out of sync
5415b1cd21fSOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, CCR, voice + 1, ccr);
5421da177e4SLinus Torvalds 	}
5435b1cd21fSOswald Buddenhagen 	snd_emu10k1_ptr_write(emu, CCR, voice, ccr);
5441da177e4SLinus Torvalds }
5451da177e4SLinus Torvalds 
5469581128aSOswald Buddenhagen static void snd_emu10k1_playback_prepare_voices(struct snd_emu10k1 *emu,
5479581128aSOswald Buddenhagen 						struct snd_emu10k1_pcm *epcm,
5489581128aSOswald Buddenhagen 						bool w_16, bool stereo,
5499581128aSOswald Buddenhagen 						int channels)
5509581128aSOswald Buddenhagen {
551fa75064dSOswald Buddenhagen 	struct snd_pcm_substream *substream = epcm->substream;
552fa75064dSOswald Buddenhagen 	struct snd_pcm_runtime *runtime = substream->runtime;
553fa75064dSOswald Buddenhagen 	unsigned eloop_start = epcm->start_addr >> w_16;
554fa75064dSOswald Buddenhagen 	unsigned loop_start = eloop_start >> stereo;
555fa75064dSOswald Buddenhagen 	unsigned eloop_size = runtime->period_size;
556fa75064dSOswald Buddenhagen 	unsigned loop_size = runtime->buffer_size;
5579581128aSOswald Buddenhagen 	u32 sample = w_16 ? 0 : 0x80808080;
5589581128aSOswald Buddenhagen 
559fa75064dSOswald Buddenhagen 	// To make the playback actually start at the 1st frame,
560fa75064dSOswald Buddenhagen 	// we need to compensate for two circumstances:
561fa75064dSOswald Buddenhagen 	// - The actual position is delayed by the cache size (64 frames)
562fa75064dSOswald Buddenhagen 	// - The interpolator is centered around the 4th frame
56311ee59bdSOswald Buddenhagen 	loop_start += (epcm->resume_pos + 64 - 3) % loop_size;
5649581128aSOswald Buddenhagen 	for (int i = 0; i < channels; i++) {
5659581128aSOswald Buddenhagen 		unsigned voice = epcm->voices[i]->number;
566fa75064dSOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, voice, loop_start);
567fa75064dSOswald Buddenhagen 		loop_start += loop_size;
5689581128aSOswald Buddenhagen 		snd_emu10k1_playback_fill_cache(emu, voice, sample, stereo);
5699581128aSOswald Buddenhagen 	}
5709581128aSOswald Buddenhagen 
571fa75064dSOswald Buddenhagen 	// The interrupt is triggered when CCCA_CURRADDR (CA) wraps around,
572fa75064dSOswald Buddenhagen 	// which is ahead of the actual playback position, so the interrupt
573fa75064dSOswald Buddenhagen 	// source needs to be delayed.
574fa75064dSOswald Buddenhagen 	//
575fa75064dSOswald Buddenhagen 	// In principle, this wouldn't need to be the cache's entire size - in
576fa75064dSOswald Buddenhagen 	// practice, CCR_CACHEINVALIDSIZE (CIS) > `fetch threshold` has never
577fa75064dSOswald Buddenhagen 	// been observed, and assuming 40 _bytes_ should be safe.
578fa75064dSOswald Buddenhagen 	//
579fa75064dSOswald Buddenhagen 	// The cache fills are somewhat random, which makes it impossible to
580fa75064dSOswald Buddenhagen 	// align them with the interrupts. This makes a non-delayed interrupt
581fa75064dSOswald Buddenhagen 	// source not practical, as the interrupt handler would have to wait
582fa75064dSOswald Buddenhagen 	// for (CA - CIS) >= period_boundary for every channel in the stream.
583fa75064dSOswald Buddenhagen 	//
584fa75064dSOswald Buddenhagen 	// This is why all other (open) drivers for these chips use timer-based
585fa75064dSOswald Buddenhagen 	// interrupts.
586fa75064dSOswald Buddenhagen 	//
58711ee59bdSOswald Buddenhagen 	eloop_start += (epcm->resume_pos + eloop_size - 3) % eloop_size;
588fa75064dSOswald Buddenhagen 	snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, epcm->extra->number, eloop_start);
589fa75064dSOswald Buddenhagen 
5909581128aSOswald Buddenhagen 	// It takes a moment until the cache fills complete,
5919581128aSOswald Buddenhagen 	// but the unmuting takes long enough for that.
5929581128aSOswald Buddenhagen }
5939581128aSOswald Buddenhagen 
59477e067d0SOswald Buddenhagen static void snd_emu10k1_playback_commit_volume(struct snd_emu10k1 *emu,
59577e067d0SOswald Buddenhagen 					       struct snd_emu10k1_voice *evoice,
59677e067d0SOswald Buddenhagen 					       unsigned int vattn)
59777e067d0SOswald Buddenhagen {
59846055699SOswald Buddenhagen 	snd_emu10k1_ptr_write_multiple(emu, evoice->number,
59946055699SOswald Buddenhagen 		VTFT, vattn | VTFT_FILTERTARGET_MASK,
60046055699SOswald Buddenhagen 		CVCF, vattn | CVCF_CURRENTFILTER_MASK,
60146055699SOswald Buddenhagen 		REGLIST_END);
60277e067d0SOswald Buddenhagen }
60377e067d0SOswald Buddenhagen 
60477e067d0SOswald Buddenhagen static void snd_emu10k1_playback_unmute_voice(struct snd_emu10k1 *emu,
60577e067d0SOswald Buddenhagen 					      struct snd_emu10k1_voice *evoice,
6069e72666bSOswald Buddenhagen 					      bool stereo, bool master,
607eb4698f3STakashi Iwai 					      struct snd_emu10k1_pcm_mixer *mix)
6081da177e4SLinus Torvalds {
60994dabafeSOswald Buddenhagen 	unsigned int vattn;
61077e067d0SOswald Buddenhagen 	unsigned int tmp;
6111da177e4SLinus Torvalds 
6129e72666bSOswald Buddenhagen 	tmp = stereo ? (master ? 1 : 2) : 0;
61377e067d0SOswald Buddenhagen 	vattn = mix->attn[tmp] << 16;
61477e067d0SOswald Buddenhagen 	snd_emu10k1_playback_commit_volume(emu, evoice, vattn);
61577e067d0SOswald Buddenhagen }
61677e067d0SOswald Buddenhagen 
617f5192e33SOswald Buddenhagen static void snd_emu10k1_playback_unmute_voices(struct snd_emu10k1 *emu,
618f5192e33SOswald Buddenhagen 					       struct snd_emu10k1_voice *evoice,
619f5192e33SOswald Buddenhagen 					       bool stereo,
620f5192e33SOswald Buddenhagen 					       struct snd_emu10k1_pcm_mixer *mix)
621f5192e33SOswald Buddenhagen {
622f5192e33SOswald Buddenhagen 	snd_emu10k1_playback_unmute_voice(emu, evoice, stereo, true, mix);
623f5192e33SOswald Buddenhagen 	if (stereo)
624f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_unmute_voice(emu, evoice + 1, true, false, mix);
625f5192e33SOswald Buddenhagen }
626f5192e33SOswald Buddenhagen 
62777e067d0SOswald Buddenhagen static void snd_emu10k1_playback_mute_voice(struct snd_emu10k1 *emu,
62877e067d0SOswald Buddenhagen 					    struct snd_emu10k1_voice *evoice)
62977e067d0SOswald Buddenhagen {
63077e067d0SOswald Buddenhagen 	snd_emu10k1_playback_commit_volume(emu, evoice, 0);
6311da177e4SLinus Torvalds }
6321da177e4SLinus Torvalds 
633f5192e33SOswald Buddenhagen static void snd_emu10k1_playback_mute_voices(struct snd_emu10k1 *emu,
634f5192e33SOswald Buddenhagen 					     struct snd_emu10k1_voice *evoice,
635f5192e33SOswald Buddenhagen 					     bool stereo)
636f5192e33SOswald Buddenhagen {
637f5192e33SOswald Buddenhagen 	snd_emu10k1_playback_mute_voice(emu, evoice);
638f5192e33SOswald Buddenhagen 	if (stereo)
639f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_mute_voice(emu, evoice + 1);
640f5192e33SOswald Buddenhagen }
641f5192e33SOswald Buddenhagen 
64208e55ae9SOswald Buddenhagen static void snd_emu10k1_playback_commit_pitch(struct snd_emu10k1 *emu,
64308e55ae9SOswald Buddenhagen 					      u32 voice, u32 pitch_target)
64408e55ae9SOswald Buddenhagen {
64508e55ae9SOswald Buddenhagen 	u32 ptrx = snd_emu10k1_ptr_read(emu, PTRX, voice);
64608e55ae9SOswald Buddenhagen 	u32 cpf = snd_emu10k1_ptr_read(emu, CPF, voice);
64708e55ae9SOswald Buddenhagen 	snd_emu10k1_ptr_write_multiple(emu, voice,
64808e55ae9SOswald Buddenhagen 		PTRX, (ptrx & ~PTRX_PITCHTARGET_MASK) | pitch_target,
64908e55ae9SOswald Buddenhagen 		CPF, (cpf & ~(CPF_CURRENTPITCH_MASK | CPF_FRACADDRESS_MASK)) | pitch_target,
65008e55ae9SOswald Buddenhagen 		REGLIST_END);
65108e55ae9SOswald Buddenhagen }
65208e55ae9SOswald Buddenhagen 
65335a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu,
65477e067d0SOswald Buddenhagen 					       struct snd_emu10k1_voice *evoice)
6551da177e4SLinus Torvalds {
656eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream;
657eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime;
65894dabafeSOswald Buddenhagen 	unsigned int voice, pitch_target;
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 	substream = evoice->epcm->substream;
6611da177e4SLinus Torvalds 	runtime = substream->runtime;
6621da177e4SLinus Torvalds 	voice = evoice->number;
6631da177e4SLinus Torvalds 
664190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model)
665b0dbdaeaSJames Courtier-Dutton 		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
666b0dbdaeaSJames Courtier-Dutton 	else
6671da177e4SLinus Torvalds 		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
66808e55ae9SOswald Buddenhagen 	snd_emu10k1_playback_commit_pitch(emu, voice, pitch_target << 16);
6691da177e4SLinus Torvalds }
6701da177e4SLinus Torvalds 
67135a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu,
67235a60d1eSOswald Buddenhagen 					    struct snd_emu10k1_voice *evoice)
6731da177e4SLinus Torvalds {
6741da177e4SLinus Torvalds 	unsigned int voice;
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 	voice = evoice->number;
67708e55ae9SOswald Buddenhagen 	snd_emu10k1_playback_commit_pitch(emu, voice, 0);
6781da177e4SLinus Torvalds }
6791da177e4SLinus Torvalds 
68035a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_set_running(struct snd_emu10k1 *emu,
68135a60d1eSOswald Buddenhagen 					     struct snd_emu10k1_pcm *epcm)
68235a60d1eSOswald Buddenhagen {
68335a60d1eSOswald Buddenhagen 	epcm->running = 1;
68435a60d1eSOswald Buddenhagen 	snd_emu10k1_voice_intr_enable(emu, epcm->extra->number);
68535a60d1eSOswald Buddenhagen }
68635a60d1eSOswald Buddenhagen 
68735a60d1eSOswald Buddenhagen static void snd_emu10k1_playback_set_stopped(struct snd_emu10k1 *emu,
68835a60d1eSOswald Buddenhagen 					      struct snd_emu10k1_pcm *epcm)
68935a60d1eSOswald Buddenhagen {
69035a60d1eSOswald Buddenhagen 	snd_emu10k1_voice_intr_disable(emu, epcm->extra->number);
69135a60d1eSOswald Buddenhagen 	epcm->running = 0;
69235a60d1eSOswald Buddenhagen }
69335a60d1eSOswald Buddenhagen 
694eb4698f3STakashi Iwai static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
6951da177e4SLinus Torvalds 				        int cmd)
6961da177e4SLinus Torvalds {
697eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
698eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
699eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
700eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
7019e72666bSOswald Buddenhagen 	bool w_16 = snd_pcm_format_width(runtime->format) == 16;
7029e72666bSOswald Buddenhagen 	bool stereo = runtime->channels == 2;
7031da177e4SLinus Torvalds 	int result = 0;
7041da177e4SLinus Torvalds 
70528a97c19STakashi Iwai 	/*
7066f002b02STakashi Iwai 	dev_dbg(emu->card->dev,
7076f002b02STakashi Iwai 		"trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
70828a97c19STakashi Iwai 	       (int)emu, cmd, substream->ops->pointer(substream))
70928a97c19STakashi Iwai 	*/
7101da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
7111da177e4SLinus Torvalds 	switch (cmd) {
7121da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
7139581128aSOswald Buddenhagen 		snd_emu10k1_playback_prepare_voices(emu, epcm, w_16, stereo, 1);
714c0dbbdadSGustavo A. R. Silva 		fallthrough;
7151da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
71609668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
7171da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[substream->number];
718f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_unmute_voices(emu, epcm->voices[0], stereo, mix);
71935a60d1eSOswald Buddenhagen 		snd_emu10k1_playback_set_running(emu, epcm);
72077e067d0SOswald Buddenhagen 		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0]);
72177e067d0SOswald Buddenhagen 		snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
7221da177e4SLinus Torvalds 		break;
7231da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
7241da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
72509668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
7261da177e4SLinus Torvalds 		snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]);
7271da177e4SLinus Torvalds 		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
72835a60d1eSOswald Buddenhagen 		snd_emu10k1_playback_set_stopped(emu, epcm);
729f5192e33SOswald Buddenhagen 		snd_emu10k1_playback_mute_voices(emu, epcm->voices[0], stereo);
7301da177e4SLinus Torvalds 		break;
7311da177e4SLinus Torvalds 	default:
7321da177e4SLinus Torvalds 		result = -EINVAL;
7331da177e4SLinus Torvalds 		break;
7341da177e4SLinus Torvalds 	}
7351da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
7361da177e4SLinus Torvalds 	return result;
7371da177e4SLinus Torvalds }
7381da177e4SLinus Torvalds 
739eb4698f3STakashi Iwai static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
7401da177e4SLinus Torvalds 				       int cmd)
7411da177e4SLinus Torvalds {
742eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
743eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
744eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
7451da177e4SLinus Torvalds 	int result = 0;
7461da177e4SLinus Torvalds 
7471da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
7481da177e4SLinus Torvalds 	switch (cmd) {
7491da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
75009668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
7519f4bd5ddSJames Courtier-Dutton 		/* hmm this should cause full and half full interrupt to be raised? */
7521da177e4SLinus Torvalds 		outl(epcm->capture_ipr, emu->port + IPR);
7531da177e4SLinus Torvalds 		snd_emu10k1_intr_enable(emu, epcm->capture_inte);
75428a97c19STakashi Iwai 		/*
7556f002b02STakashi Iwai 		dev_dbg(emu->card->dev, "adccr = 0x%x, adcbs = 0x%x\n",
75628a97c19STakashi Iwai 		       epcm->adccr, epcm->adcbs);
75728a97c19STakashi Iwai 		*/
7581da177e4SLinus Torvalds 		switch (epcm->type) {
7591da177e4SLinus Torvalds 		case CAPTURE_AC97ADC:
7601da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val);
7611da177e4SLinus Torvalds 			break;
7621da177e4SLinus Torvalds 		case CAPTURE_EFX:
7631da177e4SLinus Torvalds 			if (emu->audigy) {
76446055699SOswald Buddenhagen 				snd_emu10k1_ptr_write_multiple(emu, 0,
76546055699SOswald Buddenhagen 					A_FXWC1, epcm->capture_cr_val,
76646055699SOswald Buddenhagen 					A_FXWC2, epcm->capture_cr_val2,
76746055699SOswald Buddenhagen 					REGLIST_END);
7686f002b02STakashi Iwai 				dev_dbg(emu->card->dev,
7696f002b02STakashi Iwai 					"cr_val=0x%x, cr_val2=0x%x\n",
7706f002b02STakashi Iwai 					epcm->capture_cr_val,
7716f002b02STakashi Iwai 					epcm->capture_cr_val2);
7721da177e4SLinus Torvalds 			} else
7731da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);
7741da177e4SLinus Torvalds 			break;
7751da177e4SLinus Torvalds 		default:
7761da177e4SLinus Torvalds 			break;
7771da177e4SLinus Torvalds 		}
7781da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, epcm->capture_bs_val);
7791da177e4SLinus Torvalds 		epcm->running = 1;
7801da177e4SLinus Torvalds 		epcm->first_ptr = 1;
7811da177e4SLinus Torvalds 		break;
7821da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
78309668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
7841da177e4SLinus Torvalds 		epcm->running = 0;
7851da177e4SLinus Torvalds 		snd_emu10k1_intr_disable(emu, epcm->capture_inte);
7861da177e4SLinus Torvalds 		outl(epcm->capture_ipr, emu->port + IPR);
7871da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);
7881da177e4SLinus Torvalds 		switch (epcm->type) {
7891da177e4SLinus Torvalds 		case CAPTURE_AC97ADC:
7901da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);
7911da177e4SLinus Torvalds 			break;
7921da177e4SLinus Torvalds 		case CAPTURE_EFX:
7931da177e4SLinus Torvalds 			if (emu->audigy) {
79446055699SOswald Buddenhagen 				snd_emu10k1_ptr_write_multiple(emu, 0,
79546055699SOswald Buddenhagen 					A_FXWC1, 0,
79646055699SOswald Buddenhagen 					A_FXWC2, 0,
79746055699SOswald Buddenhagen 					REGLIST_END);
7981da177e4SLinus Torvalds 			} else
7991da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, FXWC, 0, 0);
8001da177e4SLinus Torvalds 			break;
8011da177e4SLinus Torvalds 		default:
8021da177e4SLinus Torvalds 			break;
8031da177e4SLinus Torvalds 		}
8041da177e4SLinus Torvalds 		break;
8051da177e4SLinus Torvalds 	default:
8061da177e4SLinus Torvalds 		result = -EINVAL;
8071da177e4SLinus Torvalds 	}
8081da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
8091da177e4SLinus Torvalds 	return result;
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
812eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *substream)
8131da177e4SLinus Torvalds {
814eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
815eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
816eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
817fa75064dSOswald Buddenhagen 	int ptr;
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	if (!epcm->running)
8201da177e4SLinus Torvalds 		return 0;
821fa75064dSOswald Buddenhagen 
8221da177e4SLinus Torvalds 	ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff;
823fa75064dSOswald Buddenhagen 	ptr -= epcm->ccca_start_addr;
824fa75064dSOswald Buddenhagen 
825fa75064dSOswald Buddenhagen 	// This is the size of the whole cache minus the interpolator read-ahead,
826fa75064dSOswald Buddenhagen 	// which leads us to the actual playback position.
827fa75064dSOswald Buddenhagen 	//
828fa75064dSOswald Buddenhagen 	// The cache is constantly kept mostly filled, so in principle we could
829fa75064dSOswald Buddenhagen 	// return a more advanced position representing how far the hardware has
830fa75064dSOswald Buddenhagen 	// already read the buffer, and set runtime->delay accordingly. However,
831fa75064dSOswald Buddenhagen 	// this would be slightly different for every channel (and remarkably slow
832fa75064dSOswald Buddenhagen 	// to obtain), so only a fixed worst-case value would be practical.
833fa75064dSOswald Buddenhagen 	//
834fa75064dSOswald Buddenhagen 	ptr -= 64 - 3;
835fa75064dSOswald Buddenhagen 	if (ptr < 0)
8361da177e4SLinus Torvalds 		ptr += runtime->buffer_size;
837fa75064dSOswald Buddenhagen 
83828a97c19STakashi Iwai 	/*
8396f002b02STakashi Iwai 	dev_dbg(emu->card->dev,
84056385a12SJaroslav Kysela 	       "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
84156385a12SJaroslav Kysela 	       (long)ptr, (long)runtime->buffer_size,
84256385a12SJaroslav Kysela 	       (long)runtime->period_size);
84328a97c19STakashi Iwai 	*/
8441da177e4SLinus Torvalds 	return ptr;
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds 
84711ee59bdSOswald Buddenhagen static u64 snd_emu10k1_efx_playback_voice_mask(struct snd_emu10k1_pcm *epcm,
84811ee59bdSOswald Buddenhagen 					       int channels)
84911ee59bdSOswald Buddenhagen {
85011ee59bdSOswald Buddenhagen 	u64 mask = 0;
85111ee59bdSOswald Buddenhagen 
85211ee59bdSOswald Buddenhagen 	for (int i = 0; i < channels; i++) {
85311ee59bdSOswald Buddenhagen 		int voice = epcm->voices[i]->number;
85411ee59bdSOswald Buddenhagen 		mask |= 1ULL << voice;
85511ee59bdSOswald Buddenhagen 	}
85611ee59bdSOswald Buddenhagen 	return mask;
85711ee59bdSOswald Buddenhagen }
85811ee59bdSOswald Buddenhagen 
85911ee59bdSOswald Buddenhagen static void snd_emu10k1_efx_playback_freeze_voices(struct snd_emu10k1 *emu,
86011ee59bdSOswald Buddenhagen 						   struct snd_emu10k1_pcm *epcm,
86111ee59bdSOswald Buddenhagen 						   int channels)
86211ee59bdSOswald Buddenhagen {
86311ee59bdSOswald Buddenhagen 	for (int i = 0; i < channels; i++) {
86411ee59bdSOswald Buddenhagen 		int voice = epcm->voices[i]->number;
86511ee59bdSOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, CPF_STOP, voice, 1);
86611ee59bdSOswald Buddenhagen 		snd_emu10k1_playback_commit_pitch(emu, voice, PITCH_48000 << 16);
86711ee59bdSOswald Buddenhagen 	}
86811ee59bdSOswald Buddenhagen }
86911ee59bdSOswald Buddenhagen 
87011ee59bdSOswald Buddenhagen static void snd_emu10k1_efx_playback_unmute_voices(struct snd_emu10k1 *emu,
87111ee59bdSOswald Buddenhagen 						   struct snd_emu10k1_pcm *epcm,
87211ee59bdSOswald Buddenhagen 						   int channels)
87311ee59bdSOswald Buddenhagen {
87411ee59bdSOswald Buddenhagen 	for (int i = 0; i < channels; i++)
87511ee59bdSOswald Buddenhagen 		snd_emu10k1_playback_unmute_voice(emu, epcm->voices[i], false, true,
87611ee59bdSOswald Buddenhagen 						  &emu->efx_pcm_mixer[i]);
87711ee59bdSOswald Buddenhagen }
87811ee59bdSOswald Buddenhagen 
87911ee59bdSOswald Buddenhagen static void snd_emu10k1_efx_playback_stop_voices(struct snd_emu10k1 *emu,
88011ee59bdSOswald Buddenhagen 						 struct snd_emu10k1_pcm *epcm,
88111ee59bdSOswald Buddenhagen 						 int channels)
88211ee59bdSOswald Buddenhagen {
88311ee59bdSOswald Buddenhagen 	for (int i = 0; i < channels; i++)
88411ee59bdSOswald Buddenhagen 		snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]);
88511ee59bdSOswald Buddenhagen 	snd_emu10k1_playback_set_stopped(emu, epcm);
88611ee59bdSOswald Buddenhagen 
88711ee59bdSOswald Buddenhagen 	for (int i = 0; i < channels; i++)
88811ee59bdSOswald Buddenhagen 		snd_emu10k1_playback_mute_voice(emu, epcm->voices[i]);
88911ee59bdSOswald Buddenhagen }
8901da177e4SLinus Torvalds 
891eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
8921da177e4SLinus Torvalds 				        int cmd)
8931da177e4SLinus Torvalds {
894eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
895eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
896eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
89711ee59bdSOswald Buddenhagen 	u64 mask;
8981da177e4SLinus Torvalds 	int result = 0;
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
9011da177e4SLinus Torvalds 	switch (cmd) {
9021da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
9031da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
90409668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
90511ee59bdSOswald Buddenhagen 		mask = snd_emu10k1_efx_playback_voice_mask(
906f4ab5950SOswald Buddenhagen 				epcm, runtime->channels);
90711ee59bdSOswald Buddenhagen 		for (int i = 0; i < 10; i++) {
90811ee59bdSOswald Buddenhagen 			// Note that the freeze is not interruptible, so we make no
90911ee59bdSOswald Buddenhagen 			// effort to reset the bits outside the error handling here.
91011ee59bdSOswald Buddenhagen 			snd_emu10k1_voice_set_loop_stop_multiple(emu, mask);
91111ee59bdSOswald Buddenhagen 			snd_emu10k1_efx_playback_freeze_voices(
912f4ab5950SOswald Buddenhagen 					emu, epcm, runtime->channels);
91311ee59bdSOswald Buddenhagen 			snd_emu10k1_playback_prepare_voices(
914f4ab5950SOswald Buddenhagen 					emu, epcm, true, false, runtime->channels);
91511ee59bdSOswald Buddenhagen 
91611ee59bdSOswald Buddenhagen 			// It might seem to make more sense to unmute the voices only after
91711ee59bdSOswald Buddenhagen 			// they have been started, to potentially avoid torturing the speakers
91811ee59bdSOswald Buddenhagen 			// if something goes wrong. However, we cannot unmute atomically,
91911ee59bdSOswald Buddenhagen 			// which means that we'd get some mild artifacts in the regular case.
920f4ab5950SOswald Buddenhagen 			snd_emu10k1_efx_playback_unmute_voices(emu, epcm, runtime->channels);
92177e067d0SOswald Buddenhagen 
92235a60d1eSOswald Buddenhagen 			snd_emu10k1_playback_set_running(emu, epcm);
92311ee59bdSOswald Buddenhagen 			result = snd_emu10k1_voice_clear_loop_stop_multiple_atomic(emu, mask);
92411ee59bdSOswald Buddenhagen 			if (result == 0) {
92511ee59bdSOswald Buddenhagen 				// The extra voice is allowed to lag a bit
92677e067d0SOswald Buddenhagen 				snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
92711ee59bdSOswald Buddenhagen 				goto leave;
92811ee59bdSOswald Buddenhagen 			}
92911ee59bdSOswald Buddenhagen 
93011ee59bdSOswald Buddenhagen 			snd_emu10k1_efx_playback_stop_voices(
931f4ab5950SOswald Buddenhagen 					emu, epcm, runtime->channels);
93211ee59bdSOswald Buddenhagen 
93311ee59bdSOswald Buddenhagen 			if (result != -EAGAIN)
93411ee59bdSOswald Buddenhagen 				break;
93511ee59bdSOswald Buddenhagen 			// The sync start can legitimately fail due to NMIs, etc.
93611ee59bdSOswald Buddenhagen 		}
93711ee59bdSOswald Buddenhagen 		snd_emu10k1_voice_clear_loop_stop_multiple(emu, mask);
9381da177e4SLinus Torvalds 		break;
93909668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
9401da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
9411da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
9421da177e4SLinus Torvalds 		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
94311ee59bdSOswald Buddenhagen 		snd_emu10k1_efx_playback_stop_voices(
944f4ab5950SOswald Buddenhagen 				emu, epcm, runtime->channels);
94577e067d0SOswald Buddenhagen 
94611ee59bdSOswald Buddenhagen 		epcm->resume_pos = snd_emu10k1_playback_pointer(substream);
9471da177e4SLinus Torvalds 		break;
9481da177e4SLinus Torvalds 	default:
9491da177e4SLinus Torvalds 		result = -EINVAL;
9501da177e4SLinus Torvalds 		break;
9511da177e4SLinus Torvalds 	}
95211ee59bdSOswald Buddenhagen leave:
9531da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
9541da177e4SLinus Torvalds 	return result;
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds 
9571da177e4SLinus Torvalds 
958eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *substream)
9591da177e4SLinus Torvalds {
960eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
961eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
962eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
9631da177e4SLinus Torvalds 	unsigned int ptr;
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 	if (!epcm->running)
9661da177e4SLinus Torvalds 		return 0;
9671da177e4SLinus Torvalds 	if (epcm->first_ptr) {
9689f4bd5ddSJames Courtier-Dutton 		udelay(50);	/* hack, it takes awhile until capture is started */
9691da177e4SLinus Torvalds 		epcm->first_ptr = 0;
9701da177e4SLinus Torvalds 	}
9711da177e4SLinus Torvalds 	ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff;
9721da177e4SLinus Torvalds 	return bytes_to_frames(runtime, ptr);
9731da177e4SLinus Torvalds }
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds /*
9761da177e4SLinus Torvalds  *  Playback support device description
9771da177e4SLinus Torvalds  */
9781da177e4SLinus Torvalds 
9797c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_playback =
9801da177e4SLinus Torvalds {
9811da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
9821da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
98309668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
9841da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
9851da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
9861da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000,
9871da177e4SLinus Torvalds 	.rate_min =		4000,
9881da177e4SLinus Torvalds 	.rate_max =		96000,
9891da177e4SLinus Torvalds 	.channels_min =		1,
9901da177e4SLinus Torvalds 	.channels_max =		2,
9911da177e4SLinus Torvalds 	.buffer_bytes_max =	(128*1024),
9921da177e4SLinus Torvalds 	.period_bytes_max =	(128*1024),
9936dbecb9bSOswald Buddenhagen 	.periods_min =		2,
9941da177e4SLinus Torvalds 	.periods_max =		1024,
9951da177e4SLinus Torvalds 	.fifo_size =		0,
9961da177e4SLinus Torvalds };
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds /*
9991da177e4SLinus Torvalds  *  Capture support device description
10001da177e4SLinus Torvalds  */
10011da177e4SLinus Torvalds 
10027c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_capture =
10031da177e4SLinus Torvalds {
10041da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
10051da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
100609668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
10071da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID),
10081da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
10091da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_8000_48000,
10101da177e4SLinus Torvalds 	.rate_min =		8000,
10111da177e4SLinus Torvalds 	.rate_max =		48000,
10121da177e4SLinus Torvalds 	.channels_min =		1,
10131da177e4SLinus Torvalds 	.channels_max =		2,
10141da177e4SLinus Torvalds 	.buffer_bytes_max =	(64*1024),
10151da177e4SLinus Torvalds 	.period_bytes_min =	384,
10161da177e4SLinus Torvalds 	.period_bytes_max =	(64*1024),
10171da177e4SLinus Torvalds 	.periods_min =		2,
10181da177e4SLinus Torvalds 	.periods_max =		2,
10191da177e4SLinus Torvalds 	.fifo_size =		0,
10201da177e4SLinus Torvalds };
10211da177e4SLinus Torvalds 
10227c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_capture_efx =
10239f4bd5ddSJames Courtier-Dutton {
10249f4bd5ddSJames Courtier-Dutton 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
10259f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
10269f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_INFO_RESUME |
10279f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_INFO_MMAP_VALID),
10289f4bd5ddSJames Courtier-Dutton 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
10299f4bd5ddSJames Courtier-Dutton 	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
10309f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
10319f4bd5ddSJames Courtier-Dutton 				 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
10329f4bd5ddSJames Courtier-Dutton 	.rate_min =		44100,
10339f4bd5ddSJames Courtier-Dutton 	.rate_max =		192000,
10349f4bd5ddSJames Courtier-Dutton 	.channels_min =		8,
10359f4bd5ddSJames Courtier-Dutton 	.channels_max =		8,
10369f4bd5ddSJames Courtier-Dutton 	.buffer_bytes_max =	(64*1024),
10379f4bd5ddSJames Courtier-Dutton 	.period_bytes_min =	384,
10389f4bd5ddSJames Courtier-Dutton 	.period_bytes_max =	(64*1024),
10399f4bd5ddSJames Courtier-Dutton 	.periods_min =		2,
10409f4bd5ddSJames Courtier-Dutton 	.periods_max =		2,
10419f4bd5ddSJames Courtier-Dutton 	.fifo_size =		0,
10429f4bd5ddSJames Courtier-Dutton };
10439f4bd5ddSJames Courtier-Dutton 
10441da177e4SLinus Torvalds /*
10451da177e4SLinus Torvalds  *
10461da177e4SLinus Torvalds  */
10471da177e4SLinus Torvalds 
1048eb4698f3STakashi Iwai static void snd_emu10k1_pcm_mixer_notify1(struct snd_emu10k1 *emu, struct snd_kcontrol *kctl, int idx, int activate)
10491da177e4SLinus Torvalds {
1050eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
10511da177e4SLinus Torvalds 
10527c22f1aaSTakashi Iwai 	if (! kctl)
10537c22f1aaSTakashi Iwai 		return;
10541da177e4SLinus Torvalds 	if (activate)
10551da177e4SLinus Torvalds 		kctl->vd[idx].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
10561da177e4SLinus Torvalds 	else
10571da177e4SLinus Torvalds 		kctl->vd[idx].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
10581da177e4SLinus Torvalds 	snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
10591da177e4SLinus Torvalds 		       SNDRV_CTL_EVENT_MASK_INFO,
10601da177e4SLinus Torvalds 		       snd_ctl_build_ioff(&id, kctl, idx));
10611da177e4SLinus Torvalds }
10621da177e4SLinus Torvalds 
1063eb4698f3STakashi Iwai static void snd_emu10k1_pcm_mixer_notify(struct snd_emu10k1 *emu, int idx, int activate)
10641da177e4SLinus Torvalds {
10651da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_routing, idx, activate);
10661da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_volume, idx, activate);
10671da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_attn, idx, activate);
10681da177e4SLinus Torvalds }
10691da177e4SLinus Torvalds 
1070eb4698f3STakashi Iwai static void snd_emu10k1_pcm_efx_mixer_notify(struct snd_emu10k1 *emu, int idx, int activate)
10711da177e4SLinus Torvalds {
10721da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_routing, idx, activate);
10731da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_volume, idx, activate);
10741da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_attn, idx, activate);
10751da177e4SLinus Torvalds }
10761da177e4SLinus Torvalds 
1077eb4698f3STakashi Iwai static void snd_emu10k1_pcm_free_substream(struct snd_pcm_runtime *runtime)
10781da177e4SLinus Torvalds {
10794d572776SJesper Juhl 	kfree(runtime->private_data);
10801da177e4SLinus Torvalds }
10811da177e4SLinus Torvalds 
1082eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream)
10831da177e4SLinus Torvalds {
1084eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1085eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
10861da177e4SLinus Torvalds 	int i;
10871da177e4SLinus Torvalds 
10881da177e4SLinus Torvalds 	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
10891da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[i];
10901da177e4SLinus Torvalds 		mix->epcm = NULL;
10911da177e4SLinus Torvalds 		snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0);
10921da177e4SLinus Torvalds 	}
10931da177e4SLinus Torvalds 	return 0;
10941da177e4SLinus Torvalds }
10951da177e4SLinus Torvalds 
10960be0a62fSOswald Buddenhagen static int snd_emu10k1_playback_set_constraints(struct snd_pcm_runtime *runtime)
10970be0a62fSOswald Buddenhagen {
10980be0a62fSOswald Buddenhagen 	int err;
10990be0a62fSOswald Buddenhagen 
11000be0a62fSOswald Buddenhagen 	// The buffer size must be a multiple of the period size, to avoid a
11010be0a62fSOswald Buddenhagen 	// mismatch between the extra voice and the regular voices.
11020be0a62fSOswald Buddenhagen 	err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
11030be0a62fSOswald Buddenhagen 	if (err < 0)
11040be0a62fSOswald Buddenhagen 		return err;
11050be0a62fSOswald Buddenhagen 	// The hardware is typically the cache's size of 64 frames ahead.
11060be0a62fSOswald Buddenhagen 	// Leave enough time for actually filling up the buffer.
11070be0a62fSOswald Buddenhagen 	err = snd_pcm_hw_constraint_minmax(
11080be0a62fSOswald Buddenhagen 			runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 128, UINT_MAX);
11090be0a62fSOswald Buddenhagen 	return err;
11100be0a62fSOswald Buddenhagen }
11110be0a62fSOswald Buddenhagen 
1112eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream)
11131da177e4SLinus Torvalds {
1114eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1115eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1116eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
1117eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
11180be0a62fSOswald Buddenhagen 	int i, j, err;
11191da177e4SLinus Torvalds 
1120e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
11211da177e4SLinus Torvalds 	if (epcm == NULL)
11221da177e4SLinus Torvalds 		return -ENOMEM;
11231da177e4SLinus Torvalds 	epcm->emu = emu;
11241da177e4SLinus Torvalds 	epcm->type = PLAYBACK_EFX;
11251da177e4SLinus Torvalds 	epcm->substream = substream;
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 	runtime->private_data = epcm;
11281da177e4SLinus Torvalds 	runtime->private_free = snd_emu10k1_pcm_free_substream;
11291da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_efx_playback;
11300be0a62fSOswald Buddenhagen 	err = snd_emu10k1_playback_set_constraints(runtime);
11310be0a62fSOswald Buddenhagen 	if (err < 0) {
11320be0a62fSOswald Buddenhagen 		kfree(epcm);
11330be0a62fSOswald Buddenhagen 		return err;
11340be0a62fSOswald Buddenhagen 	}
11351da177e4SLinus Torvalds 
11361da177e4SLinus Torvalds 	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
11371da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[i];
1138155e3d3bSOswald Buddenhagen 		for (j = 0; j < 8; j++)
1139155e3d3bSOswald Buddenhagen 			mix->send_routing[0][j] = i + j;
11401da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
11411da177e4SLinus Torvalds 		mix->send_volume[0][0] = 255;
1142bcdbd3b7SOswald Buddenhagen 		mix->attn[0] = 0x8000;
11431da177e4SLinus Torvalds 		mix->epcm = epcm;
11441da177e4SLinus Torvalds 		snd_emu10k1_pcm_efx_mixer_notify(emu, i, 1);
11451da177e4SLinus Torvalds 	}
11461da177e4SLinus Torvalds 	return 0;
11471da177e4SLinus Torvalds }
11481da177e4SLinus Torvalds 
1149eb4698f3STakashi Iwai static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
11501da177e4SLinus Torvalds {
1151eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1152eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1153eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix;
1154eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1155d0ec95feSMihail Zenkov 	int i, err, sample_rate;
11561da177e4SLinus Torvalds 
1157e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
11581da177e4SLinus Torvalds 	if (epcm == NULL)
11591da177e4SLinus Torvalds 		return -ENOMEM;
11601da177e4SLinus Torvalds 	epcm->emu = emu;
11611da177e4SLinus Torvalds 	epcm->type = PLAYBACK_EMUVOICE;
11621da177e4SLinus Torvalds 	epcm->substream = substream;
11631da177e4SLinus Torvalds 	runtime->private_data = epcm;
11641da177e4SLinus Torvalds 	runtime->private_free = snd_emu10k1_pcm_free_substream;
11651da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_playback;
11660be0a62fSOswald Buddenhagen 	err = snd_emu10k1_playback_set_constraints(runtime);
116712bda107STakashi Iwai 	if (err < 0) {
11681da177e4SLinus Torvalds 		kfree(epcm);
11691da177e4SLinus Torvalds 		return err;
11701da177e4SLinus Torvalds 	}
1171d0ec95feSMihail Zenkov 	if (emu->card_capabilities->emu_model && emu->emu1010.internal_clock == 0)
1172d0ec95feSMihail Zenkov 		sample_rate = 44100;
1173d0ec95feSMihail Zenkov 	else
1174d0ec95feSMihail Zenkov 		sample_rate = 48000;
1175d0ec95feSMihail Zenkov 	err = snd_pcm_hw_rule_noresample(runtime, sample_rate);
117657e5c630SClemens Ladisch 	if (err < 0) {
117757e5c630SClemens Ladisch 		kfree(epcm);
117857e5c630SClemens Ladisch 		return err;
117957e5c630SClemens Ladisch 	}
11801da177e4SLinus Torvalds 	mix = &emu->pcm_mixer[substream->number];
1181155e3d3bSOswald Buddenhagen 	for (i = 0; i < 8; i++)
11821da177e4SLinus Torvalds 		mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i;
11831da177e4SLinus Torvalds 	memset(&mix->send_volume, 0, sizeof(mix->send_volume));
11841da177e4SLinus Torvalds 	mix->send_volume[0][0] = mix->send_volume[0][1] =
11851da177e4SLinus Torvalds 	mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
1186bcdbd3b7SOswald Buddenhagen 	mix->attn[0] = mix->attn[1] = mix->attn[2] = 0x8000;
11871da177e4SLinus Torvalds 	mix->epcm = epcm;
11881da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1);
11891da177e4SLinus Torvalds 	return 0;
11901da177e4SLinus Torvalds }
11911da177e4SLinus Torvalds 
1192eb4698f3STakashi Iwai static int snd_emu10k1_playback_close(struct snd_pcm_substream *substream)
11931da177e4SLinus Torvalds {
1194eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1195eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[substream->number];
11961da177e4SLinus Torvalds 
11971da177e4SLinus Torvalds 	mix->epcm = NULL;
11981da177e4SLinus Torvalds 	snd_emu10k1_pcm_mixer_notify(emu, substream->number, 0);
11991da177e4SLinus Torvalds 	return 0;
12001da177e4SLinus Torvalds }
12011da177e4SLinus Torvalds 
1202eb4698f3STakashi Iwai static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream)
12031da177e4SLinus Torvalds {
1204eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1205eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1206eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
12071da177e4SLinus Torvalds 
1208e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
12091da177e4SLinus Torvalds 	if (epcm == NULL)
12101da177e4SLinus Torvalds 		return -ENOMEM;
12111da177e4SLinus Torvalds 	epcm->emu = emu;
12121da177e4SLinus Torvalds 	epcm->type = CAPTURE_AC97ADC;
12131da177e4SLinus Torvalds 	epcm->substream = substream;
12141da177e4SLinus Torvalds 	epcm->capture_ipr = IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL;
12151da177e4SLinus Torvalds 	epcm->capture_inte = INTE_ADCBUFENABLE;
12161da177e4SLinus Torvalds 	epcm->capture_ba_reg = ADCBA;
12171da177e4SLinus Torvalds 	epcm->capture_bs_reg = ADCBS;
12181da177e4SLinus Torvalds 	epcm->capture_idx_reg = emu->audigy ? A_ADCIDX : ADCIDX;
12191da177e4SLinus Torvalds 	runtime->private_data = epcm;
12201da177e4SLinus Torvalds 	runtime->private_free = snd_emu10k1_pcm_free_substream;
12211da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_capture;
1222d2baa153SOswald Buddenhagen 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
1223d2baa153SOswald Buddenhagen 				   &hw_constraints_capture_buffer_sizes);
12241da177e4SLinus Torvalds 	emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt;
12251da177e4SLinus Torvalds 	emu->pcm_capture_substream = substream;
12261da177e4SLinus Torvalds 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates);
12271da177e4SLinus Torvalds 	return 0;
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
1230eb4698f3STakashi Iwai static int snd_emu10k1_capture_close(struct snd_pcm_substream *substream)
12311da177e4SLinus Torvalds {
1232eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 	emu->capture_interrupt = NULL;
12351da177e4SLinus Torvalds 	emu->pcm_capture_substream = NULL;
12361da177e4SLinus Torvalds 	return 0;
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds 
1239eb4698f3STakashi Iwai static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream)
12401da177e4SLinus Torvalds {
1241eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1242eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1243eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
12441da177e4SLinus Torvalds 
1245e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
12461da177e4SLinus Torvalds 	if (epcm == NULL)
12471da177e4SLinus Torvalds 		return -ENOMEM;
12481da177e4SLinus Torvalds 	epcm->emu = emu;
12491da177e4SLinus Torvalds 	epcm->type = CAPTURE_AC97MIC;
12501da177e4SLinus Torvalds 	epcm->substream = substream;
12511da177e4SLinus Torvalds 	epcm->capture_ipr = IPR_MICBUFFULL|IPR_MICBUFHALFFULL;
12521da177e4SLinus Torvalds 	epcm->capture_inte = INTE_MICBUFENABLE;
12531da177e4SLinus Torvalds 	epcm->capture_ba_reg = MICBA;
12541da177e4SLinus Torvalds 	epcm->capture_bs_reg = MICBS;
12551da177e4SLinus Torvalds 	epcm->capture_idx_reg = emu->audigy ? A_MICIDX : MICIDX;
12561da177e4SLinus Torvalds 	substream->runtime->private_data = epcm;
12571da177e4SLinus Torvalds 	substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
12581da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_capture;
12591da177e4SLinus Torvalds 	runtime->hw.rates = SNDRV_PCM_RATE_8000;
12601da177e4SLinus Torvalds 	runtime->hw.rate_min = runtime->hw.rate_max = 8000;
12611da177e4SLinus Torvalds 	runtime->hw.channels_min = 1;
1262d2baa153SOswald Buddenhagen 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
1263d2baa153SOswald Buddenhagen 				   &hw_constraints_capture_buffer_sizes);
12641da177e4SLinus Torvalds 	emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt;
12651da177e4SLinus Torvalds 	emu->pcm_capture_mic_substream = substream;
12661da177e4SLinus Torvalds 	return 0;
12671da177e4SLinus Torvalds }
12681da177e4SLinus Torvalds 
1269eb4698f3STakashi Iwai static int snd_emu10k1_capture_mic_close(struct snd_pcm_substream *substream)
12701da177e4SLinus Torvalds {
1271eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
12721da177e4SLinus Torvalds 
1273b09c551cSOswald Buddenhagen 	emu->capture_mic_interrupt = NULL;
12741da177e4SLinus Torvalds 	emu->pcm_capture_mic_substream = NULL;
12751da177e4SLinus Torvalds 	return 0;
12761da177e4SLinus Torvalds }
12771da177e4SLinus Torvalds 
1278eb4698f3STakashi Iwai static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
12791da177e4SLinus Torvalds {
1280eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1281eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm *epcm;
1282eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
12831da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
12841da177e4SLinus Torvalds 	int idx;
12851da177e4SLinus Torvalds 
1286e560d8d8STakashi Iwai 	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
12871da177e4SLinus Torvalds 	if (epcm == NULL)
12881da177e4SLinus Torvalds 		return -ENOMEM;
12891da177e4SLinus Torvalds 	epcm->emu = emu;
12901da177e4SLinus Torvalds 	epcm->type = CAPTURE_EFX;
12911da177e4SLinus Torvalds 	epcm->substream = substream;
12921da177e4SLinus Torvalds 	epcm->capture_ipr = IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL;
12931da177e4SLinus Torvalds 	epcm->capture_inte = INTE_EFXBUFENABLE;
12941da177e4SLinus Torvalds 	epcm->capture_ba_reg = FXBA;
12951da177e4SLinus Torvalds 	epcm->capture_bs_reg = FXBS;
12961da177e4SLinus Torvalds 	epcm->capture_idx_reg = FXIDX;
12971da177e4SLinus Torvalds 	substream->runtime->private_data = epcm;
12981da177e4SLinus Torvalds 	substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
12999f4bd5ddSJames Courtier-Dutton 	runtime->hw = snd_emu10k1_capture_efx;
13001da177e4SLinus Torvalds 	runtime->hw.rates = SNDRV_PCM_RATE_48000;
13011da177e4SLinus Torvalds 	runtime->hw.rate_min = runtime->hw.rate_max = 48000;
13021da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
1303190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
13049f4bd5ddSJames Courtier-Dutton 		/* TODO
13059f4bd5ddSJames Courtier-Dutton 		 * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
13069f4bd5ddSJames Courtier-Dutton 		 * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
13079f4bd5ddSJames Courtier-Dutton 		 * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
13089f4bd5ddSJames Courtier-Dutton 		 * rate_min = 44100,
13099f4bd5ddSJames Courtier-Dutton 		 * rate_max = 192000,
131013d45709SPavel Hofman 		 * channels_min = 16,
131113d45709SPavel Hofman 		 * channels_max = 16,
13129f4bd5ddSJames Courtier-Dutton 		 * Need to add mixer control to fix sample rate
13139f4bd5ddSJames Courtier-Dutton 		 *
131413d45709SPavel Hofman 		 * There are 32 mono channels of 16bits each.
1315a869057cSOswald Buddenhagen 		 * 24bit Audio uses 2x channels over 16bit,
1316a869057cSOswald Buddenhagen 		 * 96kHz uses 2x channels over 48kHz,
1317a869057cSOswald Buddenhagen 		 * 192kHz uses 4x channels over 48kHz.
1318a869057cSOswald Buddenhagen 		 * So, for 48kHz 24bit, one has 16 channels,
1319a869057cSOswald Buddenhagen 		 * for 96kHz 24bit, one has 8 channels,
1320a869057cSOswald Buddenhagen 		 * for 192kHz 24bit, one has 4 channels.
1321a869057cSOswald Buddenhagen 		 * 1010rev2 and 1616(m) cards have double that,
1322a869057cSOswald Buddenhagen 		 * but we don't exceed 16 channels anyway.
13239f4bd5ddSJames Courtier-Dutton 		 */
13249f4bd5ddSJames Courtier-Dutton #if 1
1325b0dbdaeaSJames Courtier-Dutton 		switch (emu->emu1010.internal_clock) {
1326b0dbdaeaSJames Courtier-Dutton 		case 0:
1327b0dbdaeaSJames Courtier-Dutton 			/* For 44.1kHz */
1328b0dbdaeaSJames Courtier-Dutton 			runtime->hw.rates = SNDRV_PCM_RATE_44100;
1329b0dbdaeaSJames Courtier-Dutton 			runtime->hw.rate_min = runtime->hw.rate_max = 44100;
133013d45709SPavel Hofman 			runtime->hw.channels_min =
133113d45709SPavel Hofman 				runtime->hw.channels_max = 16;
1332b0dbdaeaSJames Courtier-Dutton 			break;
1333b0dbdaeaSJames Courtier-Dutton 		case 1:
13349f4bd5ddSJames Courtier-Dutton 			/* For 48kHz */
13359f4bd5ddSJames Courtier-Dutton 			runtime->hw.rates = SNDRV_PCM_RATE_48000;
13369f4bd5ddSJames Courtier-Dutton 			runtime->hw.rate_min = runtime->hw.rate_max = 48000;
133713d45709SPavel Hofman 			runtime->hw.channels_min =
133813d45709SPavel Hofman 				runtime->hw.channels_max = 16;
1339b0dbdaeaSJames Courtier-Dutton 			break;
1340395d9dd5SPeter Senna Tschudin 		}
13419f4bd5ddSJames Courtier-Dutton #endif
13429f4bd5ddSJames Courtier-Dutton #if 0
13439f4bd5ddSJames Courtier-Dutton 		/* For 96kHz */
13449f4bd5ddSJames Courtier-Dutton 		runtime->hw.rates = SNDRV_PCM_RATE_96000;
13459f4bd5ddSJames Courtier-Dutton 		runtime->hw.rate_min = runtime->hw.rate_max = 96000;
13469f4bd5ddSJames Courtier-Dutton 		runtime->hw.channels_min = runtime->hw.channels_max = 4;
13479f4bd5ddSJames Courtier-Dutton #endif
13489f4bd5ddSJames Courtier-Dutton #if 0
13499f4bd5ddSJames Courtier-Dutton 		/* For 192kHz */
13509f4bd5ddSJames Courtier-Dutton 		runtime->hw.rates = SNDRV_PCM_RATE_192000;
13519f4bd5ddSJames Courtier-Dutton 		runtime->hw.rate_min = runtime->hw.rate_max = 192000;
13529f4bd5ddSJames Courtier-Dutton 		runtime->hw.channels_min = runtime->hw.channels_max = 2;
13539f4bd5ddSJames Courtier-Dutton #endif
13549f4bd5ddSJames Courtier-Dutton 		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
13559f4bd5ddSJames Courtier-Dutton 		/* efx_voices_mask[0] is expected to be zero
135613d45709SPavel Hofman  		 * efx_voices_mask[1] is expected to have 32bits set
13579f4bd5ddSJames Courtier-Dutton 		 */
13589f4bd5ddSJames Courtier-Dutton 	} else {
13591da177e4SLinus Torvalds 		runtime->hw.channels_min = runtime->hw.channels_max = 0;
13601da177e4SLinus Torvalds 		for (idx = 0; idx < nefx; idx++) {
13611da177e4SLinus Torvalds 			if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
13621da177e4SLinus Torvalds 				runtime->hw.channels_min++;
13631da177e4SLinus Torvalds 				runtime->hw.channels_max++;
13641da177e4SLinus Torvalds 			}
13651da177e4SLinus Torvalds 		}
13669f4bd5ddSJames Courtier-Dutton 	}
13671da177e4SLinus Torvalds 	epcm->capture_cr_val = emu->efx_voices_mask[0];
13681da177e4SLinus Torvalds 	epcm->capture_cr_val2 = emu->efx_voices_mask[1];
13691da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
1370d2baa153SOswald Buddenhagen 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
1371d2baa153SOswald Buddenhagen 				   &hw_constraints_capture_buffer_sizes);
13721da177e4SLinus Torvalds 	emu->capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt;
13731da177e4SLinus Torvalds 	emu->pcm_capture_efx_substream = substream;
13741da177e4SLinus Torvalds 	return 0;
13751da177e4SLinus Torvalds }
13761da177e4SLinus Torvalds 
1377eb4698f3STakashi Iwai static int snd_emu10k1_capture_efx_close(struct snd_pcm_substream *substream)
13781da177e4SLinus Torvalds {
1379eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
13801da177e4SLinus Torvalds 
1381b09c551cSOswald Buddenhagen 	emu->capture_efx_interrupt = NULL;
13821da177e4SLinus Torvalds 	emu->pcm_capture_efx_substream = NULL;
13831da177e4SLinus Torvalds 	return 0;
13841da177e4SLinus Torvalds }
13851da177e4SLinus Torvalds 
13866769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_playback_ops = {
13871da177e4SLinus Torvalds 	.open =			snd_emu10k1_playback_open,
13881da177e4SLinus Torvalds 	.close =		snd_emu10k1_playback_close,
13891da177e4SLinus Torvalds 	.hw_params =		snd_emu10k1_playback_hw_params,
13901da177e4SLinus Torvalds 	.hw_free =		snd_emu10k1_playback_hw_free,
13911da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_playback_prepare,
13921da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_playback_trigger,
13931da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_playback_pointer,
13941da177e4SLinus Torvalds };
13951da177e4SLinus Torvalds 
13966769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_capture_ops = {
13971da177e4SLinus Torvalds 	.open =			snd_emu10k1_capture_open,
13981da177e4SLinus Torvalds 	.close =		snd_emu10k1_capture_close,
13991da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_capture_prepare,
14001da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_capture_trigger,
14011da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_capture_pointer,
14021da177e4SLinus Torvalds };
14031da177e4SLinus Torvalds 
14041da177e4SLinus Torvalds /* EFX playback */
14056769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
14061da177e4SLinus Torvalds 	.open =			snd_emu10k1_efx_playback_open,
14071da177e4SLinus Torvalds 	.close =		snd_emu10k1_efx_playback_close,
14081da177e4SLinus Torvalds 	.hw_params =		snd_emu10k1_playback_hw_params,
140979852438SOswald Buddenhagen 	.hw_free =		snd_emu10k1_playback_hw_free,
14101da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_efx_playback_prepare,
14111da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_efx_playback_trigger,
1412b9468c41SOswald Buddenhagen 	.pointer =		snd_emu10k1_playback_pointer,
14131da177e4SLinus Torvalds };
14141da177e4SLinus Torvalds 
1415bb814c39SLars-Peter Clausen int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
14161da177e4SLinus Torvalds {
1417eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
1418eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream;
14191da177e4SLinus Torvalds 	int err;
14201da177e4SLinus Torvalds 
142112bda107STakashi Iwai 	err = snd_pcm_new(emu->card, "emu10k1", device, 32, 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_PLAYBACK, &snd_emu10k1_playback_ops);
14281da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_ops);
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 	pcm->info_flags = 0;
14311da177e4SLinus Torvalds 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
14321da177e4SLinus Torvalds 	strcpy(pcm->name, "ADC Capture/Standard PCM Playback");
14331da177e4SLinus Torvalds 	emu->pcm = pcm;
14341da177e4SLinus Torvalds 
1435cbf7dcd9STakashi Iwai 	/* playback substream can't use managed buffers due to alignment */
14361da177e4SLinus Torvalds 	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
14375116b94aSTakashi Iwai 		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG,
14386974f8adSTakashi Iwai 					      &emu->pci->dev,
14395116b94aSTakashi Iwai 					      64*1024, 64*1024);
14401da177e4SLinus Torvalds 
14411da177e4SLinus Torvalds 	for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
1442cbf7dcd9STakashi Iwai 		snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV,
1443cbf7dcd9STakashi Iwai 					   &emu->pci->dev, 64*1024, 64*1024);
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds 	return 0;
14461da177e4SLinus Torvalds }
14471da177e4SLinus Torvalds 
1448bb814c39SLars-Peter Clausen int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device)
14491da177e4SLinus Torvalds {
1450eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
1451eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream;
14521da177e4SLinus Torvalds 	int err;
14531da177e4SLinus Torvalds 
145412bda107STakashi Iwai 	err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm);
145512bda107STakashi Iwai 	if (err < 0)
14561da177e4SLinus Torvalds 		return err;
14571da177e4SLinus Torvalds 
14581da177e4SLinus Torvalds 	pcm->private_data = emu;
14591da177e4SLinus Torvalds 
14601da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_efx_playback_ops);
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 	pcm->info_flags = 0;
14631da177e4SLinus Torvalds 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
14641da177e4SLinus Torvalds 	strcpy(pcm->name, "Multichannel Playback");
146509668b44STakashi Iwai 	emu->pcm_multi = pcm;
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds 	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
14685116b94aSTakashi Iwai 		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG,
14696974f8adSTakashi Iwai 					      &emu->pci->dev,
14705116b94aSTakashi Iwai 					      64*1024, 64*1024);
14711da177e4SLinus Torvalds 
14721da177e4SLinus Torvalds 	return 0;
14731da177e4SLinus Torvalds }
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 
14766769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_capture_mic_ops = {
14771da177e4SLinus Torvalds 	.open =			snd_emu10k1_capture_mic_open,
14781da177e4SLinus Torvalds 	.close =		snd_emu10k1_capture_mic_close,
14791da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_capture_prepare,
14801da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_capture_trigger,
14811da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_capture_pointer,
14821da177e4SLinus Torvalds };
14831da177e4SLinus Torvalds 
1484bb814c39SLars-Peter Clausen int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device)
14851da177e4SLinus Torvalds {
1486eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
14871da177e4SLinus Torvalds 	int err;
14881da177e4SLinus Torvalds 
148912bda107STakashi Iwai 	err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm);
149012bda107STakashi Iwai 	if (err < 0)
14911da177e4SLinus Torvalds 		return err;
14921da177e4SLinus Torvalds 
14931da177e4SLinus Torvalds 	pcm->private_data = emu;
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops);
14961da177e4SLinus Torvalds 
14971da177e4SLinus Torvalds 	pcm->info_flags = 0;
14981da177e4SLinus Torvalds 	strcpy(pcm->name, "Mic Capture");
14991da177e4SLinus Torvalds 	emu->pcm_mic = pcm;
15001da177e4SLinus Torvalds 
1501cbf7dcd9STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
15025116b94aSTakashi Iwai 				       64*1024, 64*1024);
15031da177e4SLinus Torvalds 
15041da177e4SLinus Torvalds 	return 0;
15051da177e4SLinus Torvalds }
15061da177e4SLinus Torvalds 
1507eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15081da177e4SLinus Torvalds {
1509eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15101da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
15111da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
15121da177e4SLinus Torvalds 	uinfo->count = nefx;
15131da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15141da177e4SLinus Torvalds 	uinfo->value.integer.max = 1;
15151da177e4SLinus Torvalds 	return 0;
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds 
1518eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15191da177e4SLinus Torvalds {
1520eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15211da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
15221da177e4SLinus Torvalds 	int idx;
15231da177e4SLinus Torvalds 
15241da177e4SLinus Torvalds 	for (idx = 0; idx < nefx; idx++)
15251da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0;
15261da177e4SLinus Torvalds 	return 0;
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds 
1529eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15301da177e4SLinus Torvalds {
1531eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15321da177e4SLinus Torvalds 	unsigned int nval[2], bits;
15331da177e4SLinus Torvalds 	int nefx = emu->audigy ? 64 : 32;
15341da177e4SLinus Torvalds 	int nefxb = emu->audigy ? 7 : 6;
15351da177e4SLinus Torvalds 	int change, idx;
15361da177e4SLinus Torvalds 
15371da177e4SLinus Torvalds 	nval[0] = nval[1] = 0;
15381da177e4SLinus Torvalds 	for (idx = 0, bits = 0; idx < nefx; idx++)
15391da177e4SLinus Torvalds 		if (ucontrol->value.integer.value[idx]) {
15401da177e4SLinus Torvalds 			nval[idx / 32] |= 1 << (idx % 32);
15411da177e4SLinus Torvalds 			bits++;
15421da177e4SLinus Torvalds 		}
15431da177e4SLinus Torvalds 
1544a869057cSOswald Buddenhagen 	// Check that the number of requested channels is a power of two
1545a869057cSOswald Buddenhagen 	// not bigger than the number of available channels.
15461da177e4SLinus Torvalds 	for (idx = 0; idx < nefxb; idx++)
15471da177e4SLinus Torvalds 		if (1 << idx == bits)
15481da177e4SLinus Torvalds 			break;
15491da177e4SLinus Torvalds 	if (idx >= nefxb)
15501da177e4SLinus Torvalds 		return -EINVAL;
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
15531da177e4SLinus Torvalds 	change = (nval[0] != emu->efx_voices_mask[0]) ||
15541da177e4SLinus Torvalds 		(nval[1] != emu->efx_voices_mask[1]);
15551da177e4SLinus Torvalds 	emu->efx_voices_mask[0] = nval[0];
15561da177e4SLinus Torvalds 	emu->efx_voices_mask[1] = nval[1];
15571da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
15581da177e4SLinus Torvalds 	return change;
15591da177e4SLinus Torvalds }
15601da177e4SLinus Torvalds 
1561f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = {
15621da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
15631da177e4SLinus Torvalds 	.name = "Captured FX8010 Outputs",
15641da177e4SLinus Torvalds 	.info = snd_emu10k1_pcm_efx_voices_mask_info,
15651da177e4SLinus Torvalds 	.get = snd_emu10k1_pcm_efx_voices_mask_get,
15661da177e4SLinus Torvalds 	.put = snd_emu10k1_pcm_efx_voices_mask_put
15671da177e4SLinus Torvalds };
15681da177e4SLinus Torvalds 
15696769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_capture_efx_ops = {
15701da177e4SLinus Torvalds 	.open =			snd_emu10k1_capture_efx_open,
15711da177e4SLinus Torvalds 	.close =		snd_emu10k1_capture_efx_close,
15721da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_capture_prepare,
15731da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_capture_trigger,
15741da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_capture_pointer,
15751da177e4SLinus Torvalds };
15761da177e4SLinus Torvalds 
15771da177e4SLinus Torvalds 
15781da177e4SLinus Torvalds /* EFX playback */
15791da177e4SLinus Torvalds 
15801da177e4SLinus Torvalds #define INITIAL_TRAM_SHIFT     14
15811da177e4SLinus Torvalds #define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1)
15821da177e4SLinus Torvalds 
1583eb4698f3STakashi Iwai static void snd_emu10k1_fx8010_playback_irq(struct snd_emu10k1 *emu, void *private_data)
15841da177e4SLinus Torvalds {
1585eb4698f3STakashi Iwai 	struct snd_pcm_substream *substream = private_data;
15861da177e4SLinus Torvalds 	snd_pcm_period_elapsed(substream);
15871da177e4SLinus Torvalds }
15881da177e4SLinus Torvalds 
15891da177e4SLinus Torvalds static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,
15901da177e4SLinus Torvalds 						   unsigned short *dst_right,
15911da177e4SLinus Torvalds 						   unsigned short *src,
15921da177e4SLinus Torvalds 						   unsigned int count,
15931da177e4SLinus Torvalds 						   unsigned int tram_shift)
15941da177e4SLinus Torvalds {
159528a97c19STakashi Iwai 	/*
15966f002b02STakashi Iwai 	dev_dbg(emu->card->dev,
15976f002b02STakashi Iwai 		"tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
159828a97c19STakashi Iwai 	       "src = 0x%p, count = 0x%x\n",
159928a97c19STakashi Iwai 	       dst_left, dst_right, src, count);
160028a97c19STakashi Iwai 	*/
16011da177e4SLinus Torvalds 	if ((tram_shift & 1) == 0) {
16021da177e4SLinus Torvalds 		while (count--) {
16031da177e4SLinus Torvalds 			*dst_left-- = *src++;
16041da177e4SLinus Torvalds 			*dst_right-- = *src++;
16051da177e4SLinus Torvalds 		}
16061da177e4SLinus Torvalds 	} else {
16071da177e4SLinus Torvalds 		while (count--) {
16081da177e4SLinus Torvalds 			*dst_right-- = *src++;
16091da177e4SLinus Torvalds 			*dst_left-- = *src++;
16101da177e4SLinus Torvalds 		}
16111da177e4SLinus Torvalds 	}
16121da177e4SLinus Torvalds }
16131da177e4SLinus Torvalds 
1614eb4698f3STakashi Iwai static void fx8010_pb_trans_copy(struct snd_pcm_substream *substream,
1615eb4698f3STakashi Iwai 				 struct snd_pcm_indirect *rec, size_t bytes)
16161da177e4SLinus Torvalds {
1617eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1618eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16191da177e4SLinus Torvalds 	unsigned int tram_size = pcm->buffer_size;
16201da177e4SLinus Torvalds 	unsigned short *src = (unsigned short *)(substream->runtime->dma_area + rec->sw_data);
16211da177e4SLinus Torvalds 	unsigned int frames = bytes >> 2, count;
16221da177e4SLinus Torvalds 	unsigned int tram_pos = pcm->tram_pos;
16231da177e4SLinus Torvalds 	unsigned int tram_shift = pcm->tram_shift;
16241da177e4SLinus Torvalds 
16251da177e4SLinus Torvalds 	while (frames > tram_pos) {
16261da177e4SLinus Torvalds 		count = tram_pos + 1;
16271da177e4SLinus Torvalds 		snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos,
16281da177e4SLinus Torvalds 						       (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2,
16291da177e4SLinus Torvalds 						       src, count, tram_shift);
16301da177e4SLinus Torvalds 		src += count * 2;
16311da177e4SLinus Torvalds 		frames -= count;
16321da177e4SLinus Torvalds 		tram_pos = (tram_size / 2) - 1;
16331da177e4SLinus Torvalds 		tram_shift++;
16341da177e4SLinus Torvalds 	}
16351da177e4SLinus Torvalds 	snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos,
16361da177e4SLinus Torvalds 					       (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2,
16371da177e4SLinus Torvalds 					       src, frames, tram_shift);
16381da177e4SLinus Torvalds 	tram_pos -= frames;
16391da177e4SLinus Torvalds 	pcm->tram_pos = tram_pos;
16401da177e4SLinus Torvalds 	pcm->tram_shift = tram_shift;
16411da177e4SLinus Torvalds }
16421da177e4SLinus Torvalds 
1643eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_transfer(struct snd_pcm_substream *substream)
16441da177e4SLinus Torvalds {
1645eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1646eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16471da177e4SLinus Torvalds 
164800277e2bSTakashi Iwai 	return snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec,
164900277e2bSTakashi Iwai 						  fx8010_pb_trans_copy);
16501da177e4SLinus Torvalds }
16511da177e4SLinus Torvalds 
1652eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_hw_free(struct snd_pcm_substream *substream)
16531da177e4SLinus Torvalds {
1654eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1655eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16561da177e4SLinus Torvalds 	unsigned int i;
16571da177e4SLinus Torvalds 
16581da177e4SLinus Torvalds 	for (i = 0; i < pcm->channels; i++)
16591da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, 0);
16601da177e4SLinus Torvalds 	return 0;
16611da177e4SLinus Torvalds }
16621da177e4SLinus Torvalds 
1663eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substream)
16641da177e4SLinus Torvalds {
1665eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1666eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1667eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16681da177e4SLinus Torvalds 	unsigned int i;
16691da177e4SLinus Torvalds 
167028a97c19STakashi Iwai 	/*
16716f002b02STakashi Iwai 	dev_dbg(emu->card->dev, "prepare: etram_pages = 0x%p, dma_area = 0x%x, "
167228a97c19STakashi Iwai 	       "buffer_size = 0x%x (0x%x)\n",
167328a97c19STakashi Iwai 	       emu->fx8010.etram_pages, runtime->dma_area,
167428a97c19STakashi Iwai 	       runtime->buffer_size, runtime->buffer_size << 2);
167528a97c19STakashi Iwai 	*/
16761da177e4SLinus Torvalds 	memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec));
16771da177e4SLinus Torvalds 	pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */
16781da177e4SLinus Torvalds 	pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
16791da177e4SLinus Torvalds 	pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size);
16801da177e4SLinus Torvalds 	pcm->tram_shift = 0;
168146055699SOswald Buddenhagen 	snd_emu10k1_ptr_write_multiple(emu, 0,
168246055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_running, 0,	/* reset */
168346055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_trigger, 0,	/* reset */
168446055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_size, runtime->buffer_size,
168546055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_ptr, 0,	/* reset ptr number */
168646055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_count, runtime->period_size,
168746055699SOswald Buddenhagen 		emu->gpr_base + pcm->gpr_tmpcount, runtime->period_size,
168846055699SOswald Buddenhagen 		REGLIST_END);
16891da177e4SLinus Torvalds 	for (i = 0; i < pcm->channels; i++)
16901da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels));
16911da177e4SLinus Torvalds 	return 0;
16921da177e4SLinus Torvalds }
16931da177e4SLinus Torvalds 
1694eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substream, int cmd)
16951da177e4SLinus Torvalds {
1696eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1697eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
16981da177e4SLinus Torvalds 	int result = 0;
16991da177e4SLinus Torvalds 
17001da177e4SLinus Torvalds 	spin_lock(&emu->reg_lock);
17011da177e4SLinus Torvalds 	switch (cmd) {
17021da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
17031da177e4SLinus Torvalds 		/* follow thru */
17041da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
170509668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
17061da177e4SLinus Torvalds #ifdef EMU10K1_SET_AC3_IEC958
17071da177e4SLinus Torvalds 	{
17081da177e4SLinus Torvalds 		int i;
17091da177e4SLinus Torvalds 		for (i = 0; i < 3; i++) {
17101da177e4SLinus Torvalds 			unsigned int bits;
17111da177e4SLinus Torvalds 			bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
17121da177e4SLinus Torvalds 			       SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS |
17131da177e4SLinus Torvalds 			       0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA;
17141da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, SPCS0 + i, 0, bits);
17151da177e4SLinus Torvalds 		}
17161da177e4SLinus Torvalds 	}
17171da177e4SLinus Torvalds #endif
17181da177e4SLinus Torvalds 		result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq);
17191da177e4SLinus Torvalds 		if (result < 0)
17201da177e4SLinus Torvalds 			goto __err;
17211da177e4SLinus Torvalds 		snd_emu10k1_fx8010_playback_transfer(substream);	/* roll the ball */
17221da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1);
17231da177e4SLinus Torvalds 		break;
17241da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
17251da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
172609668b44STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
1727057666b6STakashi Iwai 		snd_emu10k1_fx8010_unregister_irq_handler(emu, &pcm->irq);
17281da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0);
17291da177e4SLinus Torvalds 		pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size);
17301da177e4SLinus Torvalds 		pcm->tram_shift = 0;
17311da177e4SLinus Torvalds 		break;
17321da177e4SLinus Torvalds 	default:
17331da177e4SLinus Torvalds 		result = -EINVAL;
17341da177e4SLinus Torvalds 		break;
17351da177e4SLinus Torvalds 	}
17361da177e4SLinus Torvalds       __err:
17371da177e4SLinus Torvalds 	spin_unlock(&emu->reg_lock);
17381da177e4SLinus Torvalds 	return result;
17391da177e4SLinus Torvalds }
17401da177e4SLinus Torvalds 
1741eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(struct snd_pcm_substream *substream)
17421da177e4SLinus Torvalds {
1743eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1744eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
17451da177e4SLinus Torvalds 	size_t ptr; /* byte pointer */
17461da177e4SLinus Torvalds 
17471da177e4SLinus Torvalds 	if (!snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_trigger, 0))
17481da177e4SLinus Torvalds 		return 0;
17491da177e4SLinus Torvalds 	ptr = snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_ptr, 0) << 2;
17501da177e4SLinus Torvalds 	return snd_pcm_indirect_playback_pointer(substream, &pcm->pcm_rec, ptr);
17511da177e4SLinus Torvalds }
17521da177e4SLinus Torvalds 
17537c0ddf06SBhumika Goyal static const struct snd_pcm_hardware snd_emu10k1_fx8010_playback =
17541da177e4SLinus Torvalds {
17551da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
175609668b44STakashi Iwai 				 SNDRV_PCM_INFO_RESUME |
175710a23f61STakashi Iwai 				 /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE |
175810a23f61STakashi Iwai 				 SNDRV_PCM_INFO_SYNC_APPLPTR),
17591da177e4SLinus Torvalds 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
17601da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_48000,
17611da177e4SLinus Torvalds 	.rate_min =		48000,
17621da177e4SLinus Torvalds 	.rate_max =		48000,
17631da177e4SLinus Torvalds 	.channels_min =		1,
17641da177e4SLinus Torvalds 	.channels_max =		1,
17651da177e4SLinus Torvalds 	.buffer_bytes_max =	(128*1024),
17661da177e4SLinus Torvalds 	.period_bytes_min =	1024,
17671da177e4SLinus Torvalds 	.period_bytes_max =	(128*1024),
1768806d31d7STakashi Iwai 	.periods_min =		2,
17691da177e4SLinus Torvalds 	.periods_max =		1024,
17701da177e4SLinus Torvalds 	.fifo_size =		0,
17711da177e4SLinus Torvalds };
17721da177e4SLinus Torvalds 
1773eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_open(struct snd_pcm_substream *substream)
17741da177e4SLinus Torvalds {
1775eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1776eb4698f3STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
1777eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
17781da177e4SLinus Torvalds 
17791da177e4SLinus Torvalds 	runtime->hw = snd_emu10k1_fx8010_playback;
17801da177e4SLinus Torvalds 	runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels;
17811da177e4SLinus Torvalds 	runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2;
17821da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
17831da177e4SLinus Torvalds 	if (pcm->valid == 0) {
17841da177e4SLinus Torvalds 		spin_unlock_irq(&emu->reg_lock);
17851da177e4SLinus Torvalds 		return -ENODEV;
17861da177e4SLinus Torvalds 	}
17871da177e4SLinus Torvalds 	pcm->opened = 1;
17881da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
17891da177e4SLinus Torvalds 	return 0;
17901da177e4SLinus Torvalds }
17911da177e4SLinus Torvalds 
1792eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_close(struct snd_pcm_substream *substream)
17931da177e4SLinus Torvalds {
1794eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
1795eb4698f3STakashi Iwai 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
17961da177e4SLinus Torvalds 
17971da177e4SLinus Torvalds 	spin_lock_irq(&emu->reg_lock);
17981da177e4SLinus Torvalds 	pcm->opened = 0;
17991da177e4SLinus Torvalds 	spin_unlock_irq(&emu->reg_lock);
18001da177e4SLinus Torvalds 	return 0;
18011da177e4SLinus Torvalds }
18021da177e4SLinus Torvalds 
18036769e988SJulia Lawall static const struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = {
18041da177e4SLinus Torvalds 	.open =			snd_emu10k1_fx8010_playback_open,
18051da177e4SLinus Torvalds 	.close =		snd_emu10k1_fx8010_playback_close,
18061da177e4SLinus Torvalds 	.hw_free =		snd_emu10k1_fx8010_playback_hw_free,
18071da177e4SLinus Torvalds 	.prepare =		snd_emu10k1_fx8010_playback_prepare,
18081da177e4SLinus Torvalds 	.trigger =		snd_emu10k1_fx8010_playback_trigger,
18091da177e4SLinus Torvalds 	.pointer =		snd_emu10k1_fx8010_playback_pointer,
18101da177e4SLinus Torvalds 	.ack =			snd_emu10k1_fx8010_playback_transfer,
18111da177e4SLinus Torvalds };
18121da177e4SLinus Torvalds 
1813bb814c39SLars-Peter Clausen int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
18141da177e4SLinus Torvalds {
1815eb4698f3STakashi Iwai 	struct snd_pcm *pcm;
1816eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
18171da177e4SLinus Torvalds 	int err;
18181da177e4SLinus Torvalds 
18198dd13214SOswald Buddenhagen 	err = snd_pcm_new(emu->card, "emu10k1 efx", device, emu->audigy ? 0 : 8, 1, &pcm);
182012bda107STakashi Iwai 	if (err < 0)
18211da177e4SLinus Torvalds 		return err;
18221da177e4SLinus Torvalds 
18231da177e4SLinus Torvalds 	pcm->private_data = emu;
18241da177e4SLinus Torvalds 
18258dd13214SOswald Buddenhagen 	if (!emu->audigy)
18261da177e4SLinus Torvalds 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops);
18271da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops);
18281da177e4SLinus Torvalds 
18291da177e4SLinus Torvalds 	pcm->info_flags = 0;
18308dd13214SOswald Buddenhagen 	if (emu->audigy)
18318dd13214SOswald Buddenhagen 		strcpy(pcm->name, "Multichannel Capture");
18328dd13214SOswald Buddenhagen 	else
18331da177e4SLinus Torvalds 		strcpy(pcm->name, "Multichannel Capture/PT Playback");
18341da177e4SLinus Torvalds 	emu->pcm_efx = pcm;
18351da177e4SLinus Torvalds 
18361da177e4SLinus Torvalds 	/* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs
18371da177e4SLinus Torvalds 	 * to these
18381da177e4SLinus Torvalds 	 */
18391da177e4SLinus Torvalds 
18401da177e4SLinus Torvalds 	if (emu->audigy) {
18411da177e4SLinus Torvalds 		emu->efx_voices_mask[0] = 0;
1842190d2c46SJames Courtier-Dutton 		if (emu->card_capabilities->emu_model)
184313d45709SPavel Hofman 			/* Pavel Hofman - 32 voices will be used for
184413d45709SPavel Hofman 			 * capture (write mode) -
184513d45709SPavel Hofman 			 * each bit = corresponding voice
184613d45709SPavel Hofman 			 */
184713d45709SPavel Hofman 			emu->efx_voices_mask[1] = 0xffffffff;
184813d45709SPavel Hofman 		else
18491da177e4SLinus Torvalds 			emu->efx_voices_mask[1] = 0xffff;
18501da177e4SLinus Torvalds 	} else {
18511da177e4SLinus Torvalds 		emu->efx_voices_mask[0] = 0xffff0000;
18521da177e4SLinus Torvalds 		emu->efx_voices_mask[1] = 0;
18531da177e4SLinus Torvalds 	}
185413d45709SPavel Hofman 	/* For emu1010, the control has to set 32 upper bits (voices)
185513d45709SPavel Hofman 	 * out of the 64 bits (voices) to true for the 16-channels capture
185613d45709SPavel Hofman 	 * to work correctly. Correct A_FXWC2 initial value (0xffffffff)
185713d45709SPavel Hofman 	 * is already defined but the snd_emu10k1_pcm_efx_voices_mask
185813d45709SPavel Hofman 	 * control can override this register's value.
185913d45709SPavel Hofman 	 */
186067ed4161SClemens Ladisch 	kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
186167ed4161SClemens Ladisch 	if (!kctl)
186267ed4161SClemens Ladisch 		return -ENOMEM;
186367ed4161SClemens Ladisch 	kctl->id.device = device;
18646d531e7bSZhouyang Jia 	err = snd_ctl_add(emu->card, kctl);
18656d531e7bSZhouyang Jia 	if (err < 0)
18666d531e7bSZhouyang Jia 		return err;
18671da177e4SLinus Torvalds 
1868cbf7dcd9STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
18695116b94aSTakashi Iwai 				       64*1024, 64*1024);
18701da177e4SLinus Torvalds 
18711da177e4SLinus Torvalds 	return 0;
18721da177e4SLinus Torvalds }
1873