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