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