11da177e4SLinus Torvalds /* 2*c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 31da177e4SLinus Torvalds * Creative Labs, Inc. 41da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / PCM routines 51da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * BUGS: 81da177e4SLinus Torvalds * -- 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * TODO: 111da177e4SLinus Torvalds * -- 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 141da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 151da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 161da177e4SLinus Torvalds * (at your option) any later version. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 191da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 201da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 211da177e4SLinus Torvalds * GNU General Public License for more details. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 241da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 251da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds */ 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #include <sound/driver.h> 301da177e4SLinus Torvalds #include <linux/pci.h> 311da177e4SLinus Torvalds #include <linux/delay.h> 321da177e4SLinus Torvalds #include <linux/slab.h> 331da177e4SLinus Torvalds #include <linux/time.h> 341da177e4SLinus Torvalds #include <linux/init.h> 351da177e4SLinus Torvalds #include <sound/core.h> 361da177e4SLinus Torvalds #include <sound/emu10k1.h> 371da177e4SLinus Torvalds 38eb4698f3STakashi Iwai static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu, 39eb4698f3STakashi Iwai struct snd_emu10k1_voice *voice) 401da177e4SLinus Torvalds { 41eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds if ((epcm = voice->epcm) == NULL) 441da177e4SLinus Torvalds return; 451da177e4SLinus Torvalds if (epcm->substream == NULL) 461da177e4SLinus Torvalds return; 471da177e4SLinus Torvalds #if 0 481da177e4SLinus Torvalds printk("IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n", 491da177e4SLinus Torvalds epcm->substream->runtime->hw->pointer(emu, epcm->substream), 501da177e4SLinus Torvalds snd_pcm_lib_period_bytes(epcm->substream), 511da177e4SLinus Torvalds snd_pcm_lib_buffer_bytes(epcm->substream)); 521da177e4SLinus Torvalds #endif 531da177e4SLinus Torvalds snd_pcm_period_elapsed(epcm->substream); 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 56eb4698f3STakashi Iwai static void snd_emu10k1_pcm_ac97adc_interrupt(struct snd_emu10k1 *emu, 57eb4698f3STakashi Iwai unsigned int status) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds #if 0 601da177e4SLinus Torvalds if (status & IPR_ADCBUFHALFFULL) { 611da177e4SLinus Torvalds if (emu->pcm_capture_substream->runtime->mode == SNDRV_PCM_MODE_FRAME) 621da177e4SLinus Torvalds return; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds #endif 651da177e4SLinus Torvalds snd_pcm_period_elapsed(emu->pcm_capture_substream); 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 68eb4698f3STakashi Iwai static void snd_emu10k1_pcm_ac97mic_interrupt(struct snd_emu10k1 *emu, 69eb4698f3STakashi Iwai unsigned int status) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds #if 0 721da177e4SLinus Torvalds if (status & IPR_MICBUFHALFFULL) { 731da177e4SLinus Torvalds if (emu->pcm_capture_mic_substream->runtime->mode == SNDRV_PCM_MODE_FRAME) 741da177e4SLinus Torvalds return; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds #endif 771da177e4SLinus Torvalds snd_pcm_period_elapsed(emu->pcm_capture_mic_substream); 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 80eb4698f3STakashi Iwai static void snd_emu10k1_pcm_efx_interrupt(struct snd_emu10k1 *emu, 81eb4698f3STakashi Iwai unsigned int status) 821da177e4SLinus Torvalds { 831da177e4SLinus Torvalds #if 0 841da177e4SLinus Torvalds if (status & IPR_EFXBUFHALFFULL) { 851da177e4SLinus Torvalds if (emu->pcm_capture_efx_substream->runtime->mode == SNDRV_PCM_MODE_FRAME) 861da177e4SLinus Torvalds return; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds #endif 891da177e4SLinus Torvalds snd_pcm_period_elapsed(emu->pcm_capture_efx_substream); 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 92eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_efx_playback_pointer(struct snd_pcm_substream *substream) 931da177e4SLinus Torvalds { 94eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 95eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 96eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 971da177e4SLinus Torvalds unsigned int ptr; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds if (!epcm->running) 1001da177e4SLinus Torvalds return 0; 1011da177e4SLinus Torvalds ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff; 1021da177e4SLinus Torvalds ptr += runtime->buffer_size; 1031da177e4SLinus Torvalds ptr -= epcm->ccca_start_addr; 1041da177e4SLinus Torvalds ptr %= runtime->buffer_size; 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds return ptr; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 109eb4698f3STakashi Iwai static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voices) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds int err, i; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds if (epcm->voices[1] != NULL && voices < 2) { 1141da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]); 1151da177e4SLinus Torvalds epcm->voices[1] = NULL; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds for (i = 0; i < voices; i++) { 1181da177e4SLinus Torvalds if (epcm->voices[i] == NULL) 1191da177e4SLinus Torvalds break; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds if (i == voices) 1221da177e4SLinus Torvalds return 0; /* already allocated */ 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(epcm->voices); i++) { 1251da177e4SLinus Torvalds if (epcm->voices[i]) { 1261da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); 1271da177e4SLinus Torvalds epcm->voices[i] = NULL; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds err = snd_emu10k1_voice_alloc(epcm->emu, 1311da177e4SLinus Torvalds epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX, 1321da177e4SLinus Torvalds voices, 1331da177e4SLinus Torvalds &epcm->voices[0]); 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds if (err < 0) 1361da177e4SLinus Torvalds return err; 1371da177e4SLinus Torvalds epcm->voices[0]->epcm = epcm; 1381da177e4SLinus Torvalds if (voices > 1) { 1391da177e4SLinus Torvalds for (i = 1; i < voices; i++) { 1401da177e4SLinus Torvalds epcm->voices[i] = &epcm->emu->voices[epcm->voices[0]->number + i]; 1411da177e4SLinus Torvalds epcm->voices[i]->epcm = epcm; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds if (epcm->extra == NULL) { 1451da177e4SLinus Torvalds err = snd_emu10k1_voice_alloc(epcm->emu, 1461da177e4SLinus Torvalds epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX, 1471da177e4SLinus Torvalds 1, 1481da177e4SLinus Torvalds &epcm->extra); 1491da177e4SLinus Torvalds if (err < 0) { 1509f4bd5ddSJames Courtier-Dutton /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */ 1511da177e4SLinus Torvalds for (i = 0; i < voices; i++) { 1521da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); 1531da177e4SLinus Torvalds epcm->voices[i] = NULL; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds return err; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds epcm->extra->epcm = epcm; 1581da177e4SLinus Torvalds epcm->extra->interrupt = snd_emu10k1_pcm_interrupt; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds return 0; 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds static unsigned int capture_period_sizes[31] = { 1641da177e4SLinus Torvalds 384, 448, 512, 640, 1651da177e4SLinus Torvalds 384*2, 448*2, 512*2, 640*2, 1661da177e4SLinus Torvalds 384*4, 448*4, 512*4, 640*4, 1671da177e4SLinus Torvalds 384*8, 448*8, 512*8, 640*8, 1681da177e4SLinus Torvalds 384*16, 448*16, 512*16, 640*16, 1691da177e4SLinus Torvalds 384*32, 448*32, 512*32, 640*32, 1701da177e4SLinus Torvalds 384*64, 448*64, 512*64, 640*64, 1711da177e4SLinus Torvalds 384*128,448*128,512*128 1721da177e4SLinus Torvalds }; 1731da177e4SLinus Torvalds 174eb4698f3STakashi Iwai static struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = { 1751da177e4SLinus Torvalds .count = 31, 1761da177e4SLinus Torvalds .list = capture_period_sizes, 1771da177e4SLinus Torvalds .mask = 0 1781da177e4SLinus Torvalds }; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static unsigned int capture_rates[8] = { 1811da177e4SLinus Torvalds 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 1821da177e4SLinus Torvalds }; 1831da177e4SLinus Torvalds 184eb4698f3STakashi Iwai static struct snd_pcm_hw_constraint_list hw_constraints_capture_rates = { 1851da177e4SLinus Torvalds .count = 8, 1861da177e4SLinus Torvalds .list = capture_rates, 1871da177e4SLinus Torvalds .mask = 0 1881da177e4SLinus Torvalds }; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds static unsigned int snd_emu10k1_capture_rate_reg(unsigned int rate) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds switch (rate) { 1931da177e4SLinus Torvalds case 8000: return ADCCR_SAMPLERATE_8; 1941da177e4SLinus Torvalds case 11025: return ADCCR_SAMPLERATE_11; 1951da177e4SLinus Torvalds case 16000: return ADCCR_SAMPLERATE_16; 1961da177e4SLinus Torvalds case 22050: return ADCCR_SAMPLERATE_22; 1971da177e4SLinus Torvalds case 24000: return ADCCR_SAMPLERATE_24; 1981da177e4SLinus Torvalds case 32000: return ADCCR_SAMPLERATE_32; 1991da177e4SLinus Torvalds case 44100: return ADCCR_SAMPLERATE_44; 2001da177e4SLinus Torvalds case 48000: return ADCCR_SAMPLERATE_48; 2011da177e4SLinus Torvalds default: 2021da177e4SLinus Torvalds snd_BUG(); 2031da177e4SLinus Torvalds return ADCCR_SAMPLERATE_8; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds switch (rate) { 2101da177e4SLinus Torvalds case 8000: return A_ADCCR_SAMPLERATE_8; 2111da177e4SLinus Torvalds case 11025: return A_ADCCR_SAMPLERATE_11; 2121da177e4SLinus Torvalds case 12000: return A_ADCCR_SAMPLERATE_12; /* really supported? */ 2131da177e4SLinus Torvalds case 16000: return ADCCR_SAMPLERATE_16; 2141da177e4SLinus Torvalds case 22050: return ADCCR_SAMPLERATE_22; 2151da177e4SLinus Torvalds case 24000: return ADCCR_SAMPLERATE_24; 2161da177e4SLinus Torvalds case 32000: return ADCCR_SAMPLERATE_32; 2171da177e4SLinus Torvalds case 44100: return ADCCR_SAMPLERATE_44; 2181da177e4SLinus Torvalds case 48000: return ADCCR_SAMPLERATE_48; 2191da177e4SLinus Torvalds default: 2201da177e4SLinus Torvalds snd_BUG(); 2211da177e4SLinus Torvalds return A_ADCCR_SAMPLERATE_8; 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds static unsigned int emu10k1_calc_pitch_target(unsigned int rate) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds unsigned int pitch_target; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds pitch_target = (rate << 8) / 375; 2301da177e4SLinus Torvalds pitch_target = (pitch_target >> 1) + (pitch_target & 1); 2311da177e4SLinus Torvalds return pitch_target; 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds #define PITCH_48000 0x00004000 2351da177e4SLinus Torvalds #define PITCH_96000 0x00008000 2361da177e4SLinus Torvalds #define PITCH_85000 0x00007155 2371da177e4SLinus Torvalds #define PITCH_80726 0x00006ba2 2381da177e4SLinus Torvalds #define PITCH_67882 0x00005a82 2391da177e4SLinus Torvalds #define PITCH_57081 0x00004c1c 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds static unsigned int emu10k1_select_interprom(unsigned int pitch_target) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds if (pitch_target == PITCH_48000) 2441da177e4SLinus Torvalds return CCCA_INTERPROM_0; 2451da177e4SLinus Torvalds else if (pitch_target < PITCH_48000) 2461da177e4SLinus Torvalds return CCCA_INTERPROM_1; 2471da177e4SLinus Torvalds else if (pitch_target >= PITCH_96000) 2481da177e4SLinus Torvalds return CCCA_INTERPROM_0; 2491da177e4SLinus Torvalds else if (pitch_target >= PITCH_85000) 2501da177e4SLinus Torvalds return CCCA_INTERPROM_6; 2511da177e4SLinus Torvalds else if (pitch_target >= PITCH_80726) 2521da177e4SLinus Torvalds return CCCA_INTERPROM_5; 2531da177e4SLinus Torvalds else if (pitch_target >= PITCH_67882) 2541da177e4SLinus Torvalds return CCCA_INTERPROM_4; 2551da177e4SLinus Torvalds else if (pitch_target >= PITCH_57081) 2561da177e4SLinus Torvalds return CCCA_INTERPROM_3; 2571da177e4SLinus Torvalds else 2581da177e4SLinus Torvalds return CCCA_INTERPROM_2; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds /* 2621da177e4SLinus Torvalds * calculate cache invalidate size 2631da177e4SLinus Torvalds * 2641da177e4SLinus Torvalds * stereo: channel is stereo 2651da177e4SLinus Torvalds * w_16: using 16bit samples 2661da177e4SLinus Torvalds * 2671da177e4SLinus Torvalds * returns: cache invalidate size in samples 2681da177e4SLinus Torvalds */ 269fe5ac9dcSJesper Juhl static inline int emu10k1_ccis(int stereo, int w_16) 2701da177e4SLinus Torvalds { 2711da177e4SLinus Torvalds if (w_16) { 2721da177e4SLinus Torvalds return stereo ? 24 : 26; 2731da177e4SLinus Torvalds } else { 2741da177e4SLinus Torvalds return stereo ? 24*2 : 26*2; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 278eb4698f3STakashi Iwai static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, 2791da177e4SLinus Torvalds int master, int extra, 280eb4698f3STakashi Iwai struct snd_emu10k1_voice *evoice, 2811da177e4SLinus Torvalds unsigned int start_addr, 2821da177e4SLinus Torvalds unsigned int end_addr, 283eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix) 2841da177e4SLinus Torvalds { 285eb4698f3STakashi Iwai struct snd_pcm_substream *substream = evoice->epcm->substream; 286eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 2871da177e4SLinus Torvalds unsigned int silent_page, tmp; 2881da177e4SLinus Torvalds int voice, stereo, w_16; 2891da177e4SLinus Torvalds unsigned char attn, send_amount[8]; 2901da177e4SLinus Torvalds unsigned char send_routing[8]; 2911da177e4SLinus Torvalds unsigned long flags; 2921da177e4SLinus Torvalds unsigned int pitch_target; 2931da177e4SLinus Torvalds unsigned int ccis; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds voice = evoice->number; 2961da177e4SLinus Torvalds stereo = runtime->channels == 2; 2971da177e4SLinus Torvalds w_16 = snd_pcm_format_width(runtime->format) == 16; 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds if (!extra && stereo) { 3001da177e4SLinus Torvalds start_addr >>= 1; 3011da177e4SLinus Torvalds end_addr >>= 1; 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds if (w_16) { 3041da177e4SLinus Torvalds start_addr >>= 1; 3051da177e4SLinus Torvalds end_addr >>= 1; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* volume parameters */ 3111da177e4SLinus Torvalds if (extra) { 3121da177e4SLinus Torvalds attn = 0; 3131da177e4SLinus Torvalds memset(send_routing, 0, sizeof(send_routing)); 3141da177e4SLinus Torvalds send_routing[0] = 0; 3151da177e4SLinus Torvalds send_routing[1] = 1; 3161da177e4SLinus Torvalds send_routing[2] = 2; 3171da177e4SLinus Torvalds send_routing[3] = 3; 3181da177e4SLinus Torvalds memset(send_amount, 0, sizeof(send_amount)); 3191da177e4SLinus Torvalds } else { 3201da177e4SLinus Torvalds /* mono, left, right (master voice = left) */ 3211da177e4SLinus Torvalds tmp = stereo ? (master ? 1 : 2) : 0; 3221da177e4SLinus Torvalds memcpy(send_routing, &mix->send_routing[tmp][0], 8); 3231da177e4SLinus Torvalds memcpy(send_amount, &mix->send_volume[tmp][0], 8); 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds ccis = emu10k1_ccis(stereo, w_16); 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds if (master) { 3291da177e4SLinus Torvalds evoice->epcm->ccca_start_addr = start_addr + ccis; 3301da177e4SLinus Torvalds if (extra) { 3311da177e4SLinus Torvalds start_addr += ccis; 3321da177e4SLinus Torvalds end_addr += ccis; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds if (stereo && !extra) { 3351da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); 3361da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CPF, (voice + 1), CPF_STEREO_MASK); 3371da177e4SLinus Torvalds } else { 3381da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CPF, voice, 0); 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 3429f4bd5ddSJames Courtier-Dutton /* setup routing */ 3431da177e4SLinus Torvalds if (emu->audigy) { 3441da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 3451da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(send_routing)); 3461da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 3471da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(send_routing)); 3481da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, 3491da177e4SLinus Torvalds ((unsigned int)send_amount[4] << 24) | 3501da177e4SLinus Torvalds ((unsigned int)send_amount[5] << 16) | 3511da177e4SLinus Torvalds ((unsigned int)send_amount[6] << 8) | 3521da177e4SLinus Torvalds (unsigned int)send_amount[7]); 3531da177e4SLinus Torvalds } else 3541da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 3551da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(send_routing)); 3569f4bd5ddSJames Courtier-Dutton /* Stop CA */ 3579f4bd5ddSJames Courtier-Dutton /* Assumption that PT is already 0 so no harm overwriting */ 3581da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); 3591da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); 3601da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); 361b0dbdaeaSJames Courtier-Dutton if (emu->card_capabilities->emu1010) 362b0dbdaeaSJames Courtier-Dutton pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ 363b0dbdaeaSJames Courtier-Dutton else 3641da177e4SLinus Torvalds pitch_target = emu10k1_calc_pitch_target(runtime->rate); 3651da177e4SLinus Torvalds if (extra) 3661da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | 3671da177e4SLinus Torvalds emu10k1_select_interprom(pitch_target) | 3681da177e4SLinus Torvalds (w_16 ? 0 : CCCA_8BITSELECT)); 3691da177e4SLinus Torvalds else 3701da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | 3711da177e4SLinus Torvalds emu10k1_select_interprom(pitch_target) | 3721da177e4SLinus Torvalds (w_16 ? 0 : CCCA_8BITSELECT)); 3739f4bd5ddSJames Courtier-Dutton /* Clear filter delay memory */ 3741da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, Z1, voice, 0); 3751da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, Z2, voice, 0); 3769f4bd5ddSJames Courtier-Dutton /* invalidate maps */ 3771da177e4SLinus Torvalds silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; 3781da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); 3791da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); 3809f4bd5ddSJames Courtier-Dutton /* modulation envelope */ 3811da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); 3821da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); 3831da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); 3841da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DCYSUSM, voice, 0x007f); 3851da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, LFOVAL1, voice, 0x8000); 3861da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, LFOVAL2, voice, 0x8000); 3871da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FMMOD, voice, 0); 3881da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); 3891da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); 3901da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); 3919f4bd5ddSJames Courtier-Dutton /* volume envelope */ 3921da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); 3931da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); 3949f4bd5ddSJames Courtier-Dutton /* filter envelope */ 3951da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); 3969f4bd5ddSJames Courtier-Dutton /* pitch envelope */ 3971da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 402eb4698f3STakashi Iwai static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream, 403eb4698f3STakashi Iwai struct snd_pcm_hw_params *hw_params) 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; 4081da177e4SLinus Torvalds int err; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0) 4111da177e4SLinus Torvalds return err; 4121da177e4SLinus Torvalds if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) 4131da177e4SLinus Torvalds return err; 4141da177e4SLinus Torvalds if (err > 0) { /* change */ 415e017fa57STakashi Iwai int mapped; 4161da177e4SLinus Torvalds if (epcm->memblk != NULL) 4171da177e4SLinus Torvalds snd_emu10k1_free_pages(emu, epcm->memblk); 418e017fa57STakashi Iwai epcm->memblk = snd_emu10k1_alloc_pages(emu, substream); 4191da177e4SLinus Torvalds epcm->start_addr = 0; 420e017fa57STakashi Iwai if (! epcm->memblk) 4211da177e4SLinus Torvalds return -ENOMEM; 422eb4698f3STakashi Iwai mapped = ((struct snd_emu10k1_memblk *)epcm->memblk)->mapped_page; 423e017fa57STakashi Iwai if (mapped < 0) 424e017fa57STakashi Iwai return -ENOMEM; 425e017fa57STakashi Iwai epcm->start_addr = mapped << PAGE_SHIFT; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds return 0; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 430eb4698f3STakashi Iwai static int snd_emu10k1_playback_hw_free(struct snd_pcm_substream *substream) 4311da177e4SLinus Torvalds { 432eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 433eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 434eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds if (runtime->private_data == NULL) 4371da177e4SLinus Torvalds return 0; 4381da177e4SLinus Torvalds epcm = runtime->private_data; 4391da177e4SLinus Torvalds if (epcm->extra) { 4401da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->extra); 4411da177e4SLinus Torvalds epcm->extra = NULL; 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds if (epcm->voices[1]) { 4441da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]); 4451da177e4SLinus Torvalds epcm->voices[1] = NULL; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds if (epcm->voices[0]) { 4481da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->voices[0]); 4491da177e4SLinus Torvalds epcm->voices[0] = NULL; 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds if (epcm->memblk) { 4521da177e4SLinus Torvalds snd_emu10k1_free_pages(emu, epcm->memblk); 4531da177e4SLinus Torvalds epcm->memblk = NULL; 4541da177e4SLinus Torvalds epcm->start_addr = 0; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds snd_pcm_lib_free_pages(substream); 4571da177e4SLinus Torvalds return 0; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 460eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_hw_free(struct snd_pcm_substream *substream) 4611da177e4SLinus Torvalds { 462eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 463eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 464eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 4651da177e4SLinus Torvalds int i; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds if (runtime->private_data == NULL) 4681da177e4SLinus Torvalds return 0; 4691da177e4SLinus Torvalds epcm = runtime->private_data; 4701da177e4SLinus Torvalds if (epcm->extra) { 4711da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->extra); 4721da177e4SLinus Torvalds epcm->extra = NULL; 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds for (i = 0; i < NUM_EFX_PLAYBACK; i++) { 4751da177e4SLinus Torvalds if (epcm->voices[i]) { 4761da177e4SLinus Torvalds snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); 4771da177e4SLinus Torvalds epcm->voices[i] = NULL; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds if (epcm->memblk) { 4811da177e4SLinus Torvalds snd_emu10k1_free_pages(emu, epcm->memblk); 4821da177e4SLinus Torvalds epcm->memblk = NULL; 4831da177e4SLinus Torvalds epcm->start_addr = 0; 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds snd_pcm_lib_free_pages(substream); 4861da177e4SLinus Torvalds return 0; 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds 489eb4698f3STakashi Iwai static int snd_emu10k1_playback_prepare(struct snd_pcm_substream *substream) 4901da177e4SLinus Torvalds { 491eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 492eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 493eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 4941da177e4SLinus Torvalds unsigned int start_addr, end_addr; 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds start_addr = epcm->start_addr; 4971da177e4SLinus Torvalds end_addr = snd_pcm_lib_period_bytes(substream); 4981da177e4SLinus Torvalds if (runtime->channels == 2) { 4991da177e4SLinus Torvalds start_addr >>= 1; 5001da177e4SLinus Torvalds end_addr >>= 1; 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds end_addr += start_addr; 5031da177e4SLinus Torvalds snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, 5041da177e4SLinus Torvalds start_addr, end_addr, NULL); 5051da177e4SLinus Torvalds start_addr = epcm->start_addr; 5061da177e4SLinus Torvalds end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); 5071da177e4SLinus Torvalds snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0], 5081da177e4SLinus Torvalds start_addr, end_addr, 5091da177e4SLinus Torvalds &emu->pcm_mixer[substream->number]); 5101da177e4SLinus Torvalds if (epcm->voices[1]) 5111da177e4SLinus Torvalds snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[1], 5121da177e4SLinus Torvalds start_addr, end_addr, 5131da177e4SLinus Torvalds &emu->pcm_mixer[substream->number]); 5141da177e4SLinus Torvalds return 0; 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 517eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_prepare(struct snd_pcm_substream *substream) 5181da177e4SLinus Torvalds { 519eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 520eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 521eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 5221da177e4SLinus Torvalds unsigned int start_addr, end_addr; 5231da177e4SLinus Torvalds unsigned int channel_size; 5241da177e4SLinus Torvalds int i; 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds start_addr = epcm->start_addr; 5271da177e4SLinus Torvalds end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds /* 5301da177e4SLinus Torvalds * the kX driver leaves some space between voices 5311da177e4SLinus Torvalds */ 5321da177e4SLinus Torvalds channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, 5351da177e4SLinus Torvalds start_addr, start_addr + (channel_size / 2), NULL); 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds /* only difference with the master voice is we use it for the pointer */ 5381da177e4SLinus Torvalds snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0], 5391da177e4SLinus Torvalds start_addr, start_addr + channel_size, 5401da177e4SLinus Torvalds &emu->efx_pcm_mixer[0]); 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds start_addr += channel_size; 5431da177e4SLinus Torvalds for (i = 1; i < NUM_EFX_PLAYBACK; i++) { 5441da177e4SLinus Torvalds snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[i], 5451da177e4SLinus Torvalds start_addr, start_addr + channel_size, 5461da177e4SLinus Torvalds &emu->efx_pcm_mixer[i]); 5471da177e4SLinus Torvalds start_addr += channel_size; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds return 0; 5511da177e4SLinus Torvalds } 5521da177e4SLinus Torvalds 553eb4698f3STakashi Iwai static struct snd_pcm_hardware snd_emu10k1_efx_playback = 5541da177e4SLinus Torvalds { 5551da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED | 5561da177e4SLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER | 55709668b44STakashi Iwai SNDRV_PCM_INFO_RESUME | 5581da177e4SLinus Torvalds SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), 5591da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_S16_LE, 5601da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_48000, 5611da177e4SLinus Torvalds .rate_min = 48000, 5621da177e4SLinus Torvalds .rate_max = 48000, 5631da177e4SLinus Torvalds .channels_min = NUM_EFX_PLAYBACK, 5641da177e4SLinus Torvalds .channels_max = NUM_EFX_PLAYBACK, 5651da177e4SLinus Torvalds .buffer_bytes_max = (64*1024), 5661da177e4SLinus Torvalds .period_bytes_min = 64, 5671da177e4SLinus Torvalds .period_bytes_max = (64*1024), 5681da177e4SLinus Torvalds .periods_min = 2, 5691da177e4SLinus Torvalds .periods_max = 2, 5701da177e4SLinus Torvalds .fifo_size = 0, 5711da177e4SLinus Torvalds }; 5721da177e4SLinus Torvalds 573eb4698f3STakashi Iwai static int snd_emu10k1_capture_hw_params(struct snd_pcm_substream *substream, 574eb4698f3STakashi Iwai struct snd_pcm_hw_params *hw_params) 5751da177e4SLinus Torvalds { 5761da177e4SLinus Torvalds return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 579eb4698f3STakashi Iwai static int snd_emu10k1_capture_hw_free(struct snd_pcm_substream *substream) 5801da177e4SLinus Torvalds { 5811da177e4SLinus Torvalds return snd_pcm_lib_free_pages(substream); 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 584eb4698f3STakashi Iwai static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) 5851da177e4SLinus Torvalds { 586eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 587eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 588eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 5891da177e4SLinus Torvalds int idx; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds /* zeroing the buffer size will stop capture */ 5921da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0); 5931da177e4SLinus Torvalds switch (epcm->type) { 5941da177e4SLinus Torvalds case CAPTURE_AC97ADC: 5951da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); 5961da177e4SLinus Torvalds break; 5971da177e4SLinus Torvalds case CAPTURE_EFX: 5981da177e4SLinus Torvalds if (emu->audigy) { 5991da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); 6001da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); 6011da177e4SLinus Torvalds } else 6021da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXWC, 0, 0); 6031da177e4SLinus Torvalds break; 6041da177e4SLinus Torvalds default: 6051da177e4SLinus Torvalds break; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, epcm->capture_ba_reg, 0, runtime->dma_addr); 6081da177e4SLinus Torvalds epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream); 6091da177e4SLinus Torvalds epcm->capture_bs_val = 0; 6101da177e4SLinus Torvalds for (idx = 0; idx < 31; idx++) { 6111da177e4SLinus Torvalds if (capture_period_sizes[idx] == epcm->capture_bufsize) { 6121da177e4SLinus Torvalds epcm->capture_bs_val = idx + 1; 6131da177e4SLinus Torvalds break; 6141da177e4SLinus Torvalds } 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds if (epcm->capture_bs_val == 0) { 6171da177e4SLinus Torvalds snd_BUG(); 6181da177e4SLinus Torvalds epcm->capture_bs_val++; 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds if (epcm->type == CAPTURE_AC97ADC) { 6211da177e4SLinus Torvalds epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE; 6221da177e4SLinus Torvalds if (runtime->channels > 1) 6231da177e4SLinus Torvalds epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE; 6241da177e4SLinus Torvalds epcm->capture_cr_val |= emu->audigy ? 6251da177e4SLinus Torvalds snd_emu10k1_audigy_capture_rate_reg(runtime->rate) : 6261da177e4SLinus Torvalds snd_emu10k1_capture_rate_reg(runtime->rate); 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds return 0; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds 631eb4698f3STakashi Iwai static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int extra, struct snd_emu10k1_voice *evoice) 6321da177e4SLinus Torvalds { 633eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime; 6341da177e4SLinus Torvalds unsigned int voice, stereo, i, ccis, cra = 64, cs, sample; 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds if (evoice == NULL) 6371da177e4SLinus Torvalds return; 6381da177e4SLinus Torvalds runtime = evoice->epcm->substream->runtime; 6391da177e4SLinus Torvalds voice = evoice->number; 6401da177e4SLinus Torvalds stereo = (!extra && runtime->channels == 2); 6411da177e4SLinus Torvalds sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; 6421da177e4SLinus Torvalds ccis = emu10k1_ccis(stereo, sample == 0); 6439f4bd5ddSJames Courtier-Dutton /* set cs to 2 * number of cache registers beside the invalidated */ 6441da177e4SLinus Torvalds cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; 6451da177e4SLinus Torvalds if (cs > 16) cs = 16; 6461da177e4SLinus Torvalds for (i = 0; i < cs; i++) { 6471da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample); 6481da177e4SLinus Torvalds if (stereo) { 6491da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); 6501da177e4SLinus Torvalds } 6511da177e4SLinus Torvalds } 6529f4bd5ddSJames Courtier-Dutton /* reset cache */ 6531da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); 6541da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); 6551da177e4SLinus Torvalds if (stereo) { 6561da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); 6571da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); 6581da177e4SLinus Torvalds } 6599f4bd5ddSJames Courtier-Dutton /* fill cache */ 6601da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); 6611da177e4SLinus Torvalds if (stereo) { 6621da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 666eb4698f3STakashi Iwai static void snd_emu10k1_playback_prepare_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice, 6671da177e4SLinus Torvalds int master, int extra, 668eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix) 6691da177e4SLinus Torvalds { 670eb4698f3STakashi Iwai struct snd_pcm_substream *substream; 671eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime; 6721da177e4SLinus Torvalds unsigned int attn, vattn; 6731da177e4SLinus Torvalds unsigned int voice, tmp; 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds if (evoice == NULL) /* skip second voice for mono */ 6761da177e4SLinus Torvalds return; 6771da177e4SLinus Torvalds substream = evoice->epcm->substream; 6781da177e4SLinus Torvalds runtime = substream->runtime; 6791da177e4SLinus Torvalds voice = evoice->number; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds attn = extra ? 0 : 0x00ff; 6821da177e4SLinus Torvalds tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0; 6831da177e4SLinus Torvalds vattn = mix != NULL ? (mix->attn[tmp] << 16) : 0; 6841da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, IFATN, voice, attn); 6851da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT, voice, vattn | 0xffff); 6861da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | 0xffff); 6871da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f); 6881da177e4SLinus Torvalds snd_emu10k1_voice_clear_loop_stop(emu, voice); 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 691eb4698f3STakashi Iwai static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice, int master, int extra) 6921da177e4SLinus Torvalds { 693eb4698f3STakashi Iwai struct snd_pcm_substream *substream; 694eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime; 6951da177e4SLinus Torvalds unsigned int voice, pitch, pitch_target; 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds if (evoice == NULL) /* skip second voice for mono */ 6981da177e4SLinus Torvalds return; 6991da177e4SLinus Torvalds substream = evoice->epcm->substream; 7001da177e4SLinus Torvalds runtime = substream->runtime; 7011da177e4SLinus Torvalds voice = evoice->number; 7021da177e4SLinus Torvalds 7031da177e4SLinus Torvalds pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; 704b0dbdaeaSJames Courtier-Dutton if (emu->card_capabilities->emu1010) 705b0dbdaeaSJames Courtier-Dutton pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ 706b0dbdaeaSJames Courtier-Dutton else 7071da177e4SLinus Torvalds pitch_target = emu10k1_calc_pitch_target(runtime->rate); 7081da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); 7091da177e4SLinus Torvalds if (master || evoice->epcm->type == PLAYBACK_EFX) 7101da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); 7111da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, IP, voice, pitch); 7121da177e4SLinus Torvalds if (extra) 7131da177e4SLinus Torvalds snd_emu10k1_voice_intr_enable(emu, voice); 7141da177e4SLinus Torvalds } 7151da177e4SLinus Torvalds 716eb4698f3STakashi Iwai static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice) 7171da177e4SLinus Torvalds { 7181da177e4SLinus Torvalds unsigned int voice; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds if (evoice == NULL) 7211da177e4SLinus Torvalds return; 7221da177e4SLinus Torvalds voice = evoice->number; 7231da177e4SLinus Torvalds snd_emu10k1_voice_intr_disable(emu, voice); 7241da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, 0); 7251da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, 0); 7261da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, IFATN, voice, 0xffff); 7271da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); 7281da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); 7291da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, IP, voice, 0); 7301da177e4SLinus Torvalds } 7311da177e4SLinus Torvalds 732eb4698f3STakashi Iwai static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, 7331da177e4SLinus Torvalds int cmd) 7341da177e4SLinus Torvalds { 735eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 736eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 737eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 738eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 7391da177e4SLinus Torvalds int result = 0; 7401da177e4SLinus Torvalds 7419f4bd5ddSJames Courtier-Dutton /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */ 7421da177e4SLinus Torvalds spin_lock(&emu->reg_lock); 7431da177e4SLinus Torvalds switch (cmd) { 7441da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_START: 7451da177e4SLinus Torvalds snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); /* do we need this? */ 7461da177e4SLinus Torvalds snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]); 7471da177e4SLinus Torvalds /* follow thru */ 7481da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 74909668b44STakashi Iwai case SNDRV_PCM_TRIGGER_RESUME: 7501da177e4SLinus Torvalds mix = &emu->pcm_mixer[substream->number]; 7511da177e4SLinus Torvalds snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); 7521da177e4SLinus Torvalds snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); 7531da177e4SLinus Torvalds snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); 7541da177e4SLinus Torvalds snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0); 7551da177e4SLinus Torvalds snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0); 7561da177e4SLinus Torvalds snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); 7571da177e4SLinus Torvalds epcm->running = 1; 7581da177e4SLinus Torvalds break; 7591da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_STOP: 7601da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 76109668b44STakashi Iwai case SNDRV_PCM_TRIGGER_SUSPEND: 7621da177e4SLinus Torvalds epcm->running = 0; 7631da177e4SLinus Torvalds snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]); 7641da177e4SLinus Torvalds snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]); 7651da177e4SLinus Torvalds snd_emu10k1_playback_stop_voice(emu, epcm->extra); 7661da177e4SLinus Torvalds break; 7671da177e4SLinus Torvalds default: 7681da177e4SLinus Torvalds result = -EINVAL; 7691da177e4SLinus Torvalds break; 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds spin_unlock(&emu->reg_lock); 7721da177e4SLinus Torvalds return result; 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds 775eb4698f3STakashi Iwai static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, 7761da177e4SLinus Torvalds int cmd) 7771da177e4SLinus Torvalds { 778eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 779eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 780eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 7811da177e4SLinus Torvalds int result = 0; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds spin_lock(&emu->reg_lock); 7841da177e4SLinus Torvalds switch (cmd) { 7851da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_START: 78609668b44STakashi Iwai case SNDRV_PCM_TRIGGER_RESUME: 7879f4bd5ddSJames Courtier-Dutton /* hmm this should cause full and half full interrupt to be raised? */ 7881da177e4SLinus Torvalds outl(epcm->capture_ipr, emu->port + IPR); 7891da177e4SLinus Torvalds snd_emu10k1_intr_enable(emu, epcm->capture_inte); 7909f4bd5ddSJames Courtier-Dutton /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */ 7911da177e4SLinus Torvalds switch (epcm->type) { 7921da177e4SLinus Torvalds case CAPTURE_AC97ADC: 7931da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); 7941da177e4SLinus Torvalds break; 7951da177e4SLinus Torvalds case CAPTURE_EFX: 7961da177e4SLinus Torvalds if (emu->audigy) { 7971da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); 7981da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); 7999f4bd5ddSJames Courtier-Dutton snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2); 8001da177e4SLinus Torvalds } else 8011da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); 8021da177e4SLinus Torvalds break; 8031da177e4SLinus Torvalds default: 8041da177e4SLinus Torvalds break; 8051da177e4SLinus Torvalds } 8061da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, epcm->capture_bs_val); 8071da177e4SLinus Torvalds epcm->running = 1; 8081da177e4SLinus Torvalds epcm->first_ptr = 1; 8091da177e4SLinus Torvalds break; 8101da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_STOP: 81109668b44STakashi Iwai case SNDRV_PCM_TRIGGER_SUSPEND: 8121da177e4SLinus Torvalds epcm->running = 0; 8131da177e4SLinus Torvalds snd_emu10k1_intr_disable(emu, epcm->capture_inte); 8141da177e4SLinus Torvalds outl(epcm->capture_ipr, emu->port + IPR); 8151da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0); 8161da177e4SLinus Torvalds switch (epcm->type) { 8171da177e4SLinus Torvalds case CAPTURE_AC97ADC: 8181da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); 8191da177e4SLinus Torvalds break; 8201da177e4SLinus Torvalds case CAPTURE_EFX: 8211da177e4SLinus Torvalds if (emu->audigy) { 8221da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); 8231da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); 8241da177e4SLinus Torvalds } else 8251da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXWC, 0, 0); 8261da177e4SLinus Torvalds break; 8271da177e4SLinus Torvalds default: 8281da177e4SLinus Torvalds break; 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds break; 8311da177e4SLinus Torvalds default: 8321da177e4SLinus Torvalds result = -EINVAL; 8331da177e4SLinus Torvalds } 8341da177e4SLinus Torvalds spin_unlock(&emu->reg_lock); 8351da177e4SLinus Torvalds return result; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 838eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *substream) 8391da177e4SLinus Torvalds { 840eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 841eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 842eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 8431da177e4SLinus Torvalds unsigned int ptr; 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds if (!epcm->running) 8461da177e4SLinus Torvalds return 0; 8471da177e4SLinus Torvalds ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff; 8481da177e4SLinus Torvalds #if 0 /* Perex's code */ 8491da177e4SLinus Torvalds ptr += runtime->buffer_size; 8501da177e4SLinus Torvalds ptr -= epcm->ccca_start_addr; 8511da177e4SLinus Torvalds ptr %= runtime->buffer_size; 8521da177e4SLinus Torvalds #else /* EMU10K1 Open Source code from Creative */ 8531da177e4SLinus Torvalds if (ptr < epcm->ccca_start_addr) 8541da177e4SLinus Torvalds ptr += runtime->buffer_size - epcm->ccca_start_addr; 8551da177e4SLinus Torvalds else { 8561da177e4SLinus Torvalds ptr -= epcm->ccca_start_addr; 8571da177e4SLinus Torvalds if (ptr >= runtime->buffer_size) 8581da177e4SLinus Torvalds ptr -= runtime->buffer_size; 8591da177e4SLinus Torvalds } 8601da177e4SLinus Torvalds #endif 8619f4bd5ddSJames Courtier-Dutton /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */ 8621da177e4SLinus Torvalds return ptr; 8631da177e4SLinus Torvalds } 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds 866eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, 8671da177e4SLinus Torvalds int cmd) 8681da177e4SLinus Torvalds { 869eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 870eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 871eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 8721da177e4SLinus Torvalds int i; 8731da177e4SLinus Torvalds int result = 0; 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds spin_lock(&emu->reg_lock); 8761da177e4SLinus Torvalds switch (cmd) { 8771da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_START: 8789f4bd5ddSJames Courtier-Dutton /* prepare voices */ 8791da177e4SLinus Torvalds for (i = 0; i < NUM_EFX_PLAYBACK; i++) { 8801da177e4SLinus Torvalds snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); 8831da177e4SLinus Torvalds 8841da177e4SLinus Torvalds /* follow thru */ 8851da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 88609668b44STakashi Iwai case SNDRV_PCM_TRIGGER_RESUME: 8871da177e4SLinus Torvalds snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); 8881da177e4SLinus Torvalds snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0, 0, 8891da177e4SLinus Torvalds &emu->efx_pcm_mixer[0]); 8901da177e4SLinus Torvalds for (i = 1; i < NUM_EFX_PLAYBACK; i++) 8911da177e4SLinus Torvalds snd_emu10k1_playback_prepare_voice(emu, epcm->voices[i], 0, 0, 8921da177e4SLinus Torvalds &emu->efx_pcm_mixer[i]); 8931da177e4SLinus Torvalds snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 0, 0); 8941da177e4SLinus Torvalds snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); 8951da177e4SLinus Torvalds for (i = 1; i < NUM_EFX_PLAYBACK; i++) 8961da177e4SLinus Torvalds snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0); 8971da177e4SLinus Torvalds epcm->running = 1; 8981da177e4SLinus Torvalds break; 89909668b44STakashi Iwai case SNDRV_PCM_TRIGGER_SUSPEND: 9001da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_STOP: 9011da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 9021da177e4SLinus Torvalds epcm->running = 0; 9031da177e4SLinus Torvalds for (i = 0; i < NUM_EFX_PLAYBACK; i++) { 9041da177e4SLinus Torvalds snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]); 9051da177e4SLinus Torvalds } 9061da177e4SLinus Torvalds snd_emu10k1_playback_stop_voice(emu, epcm->extra); 9071da177e4SLinus Torvalds break; 9081da177e4SLinus Torvalds default: 9091da177e4SLinus Torvalds result = -EINVAL; 9101da177e4SLinus Torvalds break; 9111da177e4SLinus Torvalds } 9121da177e4SLinus Torvalds spin_unlock(&emu->reg_lock); 9131da177e4SLinus Torvalds return result; 9141da177e4SLinus Torvalds } 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds 917eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *substream) 9181da177e4SLinus Torvalds { 919eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 920eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 921eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm = runtime->private_data; 9221da177e4SLinus Torvalds unsigned int ptr; 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds if (!epcm->running) 9251da177e4SLinus Torvalds return 0; 9261da177e4SLinus Torvalds if (epcm->first_ptr) { 9279f4bd5ddSJames Courtier-Dutton udelay(50); /* hack, it takes awhile until capture is started */ 9281da177e4SLinus Torvalds epcm->first_ptr = 0; 9291da177e4SLinus Torvalds } 9301da177e4SLinus Torvalds ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff; 9311da177e4SLinus Torvalds return bytes_to_frames(runtime, ptr); 9321da177e4SLinus Torvalds } 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds /* 9351da177e4SLinus Torvalds * Playback support device description 9361da177e4SLinus Torvalds */ 9371da177e4SLinus Torvalds 938eb4698f3STakashi Iwai static struct snd_pcm_hardware snd_emu10k1_playback = 9391da177e4SLinus Torvalds { 9401da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 9411da177e4SLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER | 94209668b44STakashi Iwai SNDRV_PCM_INFO_RESUME | 9431da177e4SLinus Torvalds SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), 9441da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 9451da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000, 9461da177e4SLinus Torvalds .rate_min = 4000, 9471da177e4SLinus Torvalds .rate_max = 96000, 9481da177e4SLinus Torvalds .channels_min = 1, 9491da177e4SLinus Torvalds .channels_max = 2, 9501da177e4SLinus Torvalds .buffer_bytes_max = (128*1024), 9511da177e4SLinus Torvalds .period_bytes_min = 64, 9521da177e4SLinus Torvalds .period_bytes_max = (128*1024), 9531da177e4SLinus Torvalds .periods_min = 1, 9541da177e4SLinus Torvalds .periods_max = 1024, 9551da177e4SLinus Torvalds .fifo_size = 0, 9561da177e4SLinus Torvalds }; 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds /* 9591da177e4SLinus Torvalds * Capture support device description 9601da177e4SLinus Torvalds */ 9611da177e4SLinus Torvalds 962eb4698f3STakashi Iwai static struct snd_pcm_hardware snd_emu10k1_capture = 9631da177e4SLinus Torvalds { 9641da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 9651da177e4SLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER | 96609668b44STakashi Iwai SNDRV_PCM_INFO_RESUME | 9671da177e4SLinus Torvalds SNDRV_PCM_INFO_MMAP_VALID), 9681da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_S16_LE, 9691da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_8000_48000, 9701da177e4SLinus Torvalds .rate_min = 8000, 9711da177e4SLinus Torvalds .rate_max = 48000, 9721da177e4SLinus Torvalds .channels_min = 1, 9731da177e4SLinus Torvalds .channels_max = 2, 9741da177e4SLinus Torvalds .buffer_bytes_max = (64*1024), 9751da177e4SLinus Torvalds .period_bytes_min = 384, 9761da177e4SLinus Torvalds .period_bytes_max = (64*1024), 9771da177e4SLinus Torvalds .periods_min = 2, 9781da177e4SLinus Torvalds .periods_max = 2, 9791da177e4SLinus Torvalds .fifo_size = 0, 9801da177e4SLinus Torvalds }; 9811da177e4SLinus Torvalds 9829f4bd5ddSJames Courtier-Dutton static struct snd_pcm_hardware snd_emu10k1_capture_efx = 9839f4bd5ddSJames Courtier-Dutton { 9849f4bd5ddSJames Courtier-Dutton .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 9859f4bd5ddSJames Courtier-Dutton SNDRV_PCM_INFO_BLOCK_TRANSFER | 9869f4bd5ddSJames Courtier-Dutton SNDRV_PCM_INFO_RESUME | 9879f4bd5ddSJames Courtier-Dutton SNDRV_PCM_INFO_MMAP_VALID), 9889f4bd5ddSJames Courtier-Dutton .formats = SNDRV_PCM_FMTBIT_S16_LE, 9899f4bd5ddSJames Courtier-Dutton .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 9909f4bd5ddSJames Courtier-Dutton SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 9919f4bd5ddSJames Courtier-Dutton SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, 9929f4bd5ddSJames Courtier-Dutton .rate_min = 44100, 9939f4bd5ddSJames Courtier-Dutton .rate_max = 192000, 9949f4bd5ddSJames Courtier-Dutton .channels_min = 8, 9959f4bd5ddSJames Courtier-Dutton .channels_max = 8, 9969f4bd5ddSJames Courtier-Dutton .buffer_bytes_max = (64*1024), 9979f4bd5ddSJames Courtier-Dutton .period_bytes_min = 384, 9989f4bd5ddSJames Courtier-Dutton .period_bytes_max = (64*1024), 9999f4bd5ddSJames Courtier-Dutton .periods_min = 2, 10009f4bd5ddSJames Courtier-Dutton .periods_max = 2, 10019f4bd5ddSJames Courtier-Dutton .fifo_size = 0, 10029f4bd5ddSJames Courtier-Dutton }; 10039f4bd5ddSJames Courtier-Dutton 10041da177e4SLinus Torvalds /* 10051da177e4SLinus Torvalds * 10061da177e4SLinus Torvalds */ 10071da177e4SLinus Torvalds 1008eb4698f3STakashi Iwai static void snd_emu10k1_pcm_mixer_notify1(struct snd_emu10k1 *emu, struct snd_kcontrol *kctl, int idx, int activate) 10091da177e4SLinus Torvalds { 1010eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 10111da177e4SLinus Torvalds 10127c22f1aaSTakashi Iwai if (! kctl) 10137c22f1aaSTakashi Iwai return; 10141da177e4SLinus Torvalds if (activate) 10151da177e4SLinus Torvalds kctl->vd[idx].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; 10161da177e4SLinus Torvalds else 10171da177e4SLinus Torvalds kctl->vd[idx].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 10181da177e4SLinus Torvalds snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE | 10191da177e4SLinus Torvalds SNDRV_CTL_EVENT_MASK_INFO, 10201da177e4SLinus Torvalds snd_ctl_build_ioff(&id, kctl, idx)); 10211da177e4SLinus Torvalds } 10221da177e4SLinus Torvalds 1023eb4698f3STakashi Iwai static void snd_emu10k1_pcm_mixer_notify(struct snd_emu10k1 *emu, int idx, int activate) 10241da177e4SLinus Torvalds { 10251da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_routing, idx, activate); 10261da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_volume, idx, activate); 10271da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_attn, idx, activate); 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds 1030eb4698f3STakashi Iwai static void snd_emu10k1_pcm_efx_mixer_notify(struct snd_emu10k1 *emu, int idx, int activate) 10311da177e4SLinus Torvalds { 10321da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_routing, idx, activate); 10331da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_volume, idx, activate); 10341da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_attn, idx, activate); 10351da177e4SLinus Torvalds } 10361da177e4SLinus Torvalds 1037eb4698f3STakashi Iwai static void snd_emu10k1_pcm_free_substream(struct snd_pcm_runtime *runtime) 10381da177e4SLinus Torvalds { 10394d572776SJesper Juhl kfree(runtime->private_data); 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds 1042eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream) 10431da177e4SLinus Torvalds { 1044eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1045eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 10461da177e4SLinus Torvalds int i; 10471da177e4SLinus Torvalds 10481da177e4SLinus Torvalds for (i = 0; i < NUM_EFX_PLAYBACK; i++) { 10491da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[i]; 10501da177e4SLinus Torvalds mix->epcm = NULL; 10511da177e4SLinus Torvalds snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0); 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds return 0; 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 1056eb4698f3STakashi Iwai static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) 10571da177e4SLinus Torvalds { 1058eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1059eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 1060eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 1061eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 10621da177e4SLinus Torvalds int i; 10631da177e4SLinus Torvalds 1064e560d8d8STakashi Iwai epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); 10651da177e4SLinus Torvalds if (epcm == NULL) 10661da177e4SLinus Torvalds return -ENOMEM; 10671da177e4SLinus Torvalds epcm->emu = emu; 10681da177e4SLinus Torvalds epcm->type = PLAYBACK_EFX; 10691da177e4SLinus Torvalds epcm->substream = substream; 10701da177e4SLinus Torvalds 10711da177e4SLinus Torvalds emu->pcm_playback_efx_substream = substream; 10721da177e4SLinus Torvalds 10731da177e4SLinus Torvalds runtime->private_data = epcm; 10741da177e4SLinus Torvalds runtime->private_free = snd_emu10k1_pcm_free_substream; 10751da177e4SLinus Torvalds runtime->hw = snd_emu10k1_efx_playback; 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds for (i = 0; i < NUM_EFX_PLAYBACK; i++) { 10781da177e4SLinus Torvalds mix = &emu->efx_pcm_mixer[i]; 10791da177e4SLinus Torvalds mix->send_routing[0][0] = i; 10801da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 10811da177e4SLinus Torvalds mix->send_volume[0][0] = 255; 10821da177e4SLinus Torvalds mix->attn[0] = 0xffff; 10831da177e4SLinus Torvalds mix->epcm = epcm; 10841da177e4SLinus Torvalds snd_emu10k1_pcm_efx_mixer_notify(emu, i, 1); 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds return 0; 10871da177e4SLinus Torvalds } 10881da177e4SLinus Torvalds 1089eb4698f3STakashi Iwai static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) 10901da177e4SLinus Torvalds { 1091eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1092eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 1093eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix; 1094eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 10951da177e4SLinus Torvalds int i, err; 10961da177e4SLinus Torvalds 1097e560d8d8STakashi Iwai epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); 10981da177e4SLinus Torvalds if (epcm == NULL) 10991da177e4SLinus Torvalds return -ENOMEM; 11001da177e4SLinus Torvalds epcm->emu = emu; 11011da177e4SLinus Torvalds epcm->type = PLAYBACK_EMUVOICE; 11021da177e4SLinus Torvalds epcm->substream = substream; 11031da177e4SLinus Torvalds runtime->private_data = epcm; 11041da177e4SLinus Torvalds runtime->private_free = snd_emu10k1_pcm_free_substream; 11051da177e4SLinus Torvalds runtime->hw = snd_emu10k1_playback; 11061da177e4SLinus Torvalds if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { 11071da177e4SLinus Torvalds kfree(epcm); 11081da177e4SLinus Torvalds return err; 11091da177e4SLinus Torvalds } 11101da177e4SLinus Torvalds if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0) { 11111da177e4SLinus Torvalds kfree(epcm); 11121da177e4SLinus Torvalds return err; 11131da177e4SLinus Torvalds } 11141da177e4SLinus Torvalds mix = &emu->pcm_mixer[substream->number]; 11151da177e4SLinus Torvalds for (i = 0; i < 4; i++) 11161da177e4SLinus Torvalds mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i; 11171da177e4SLinus Torvalds memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 11181da177e4SLinus Torvalds mix->send_volume[0][0] = mix->send_volume[0][1] = 11191da177e4SLinus Torvalds mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 11201da177e4SLinus Torvalds mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 11211da177e4SLinus Torvalds mix->epcm = epcm; 11221da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1); 11231da177e4SLinus Torvalds return 0; 11241da177e4SLinus Torvalds } 11251da177e4SLinus Torvalds 1126eb4698f3STakashi Iwai static int snd_emu10k1_playback_close(struct snd_pcm_substream *substream) 11271da177e4SLinus Torvalds { 1128eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1129eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[substream->number]; 11301da177e4SLinus Torvalds 11311da177e4SLinus Torvalds mix->epcm = NULL; 11321da177e4SLinus Torvalds snd_emu10k1_pcm_mixer_notify(emu, substream->number, 0); 11331da177e4SLinus Torvalds return 0; 11341da177e4SLinus Torvalds } 11351da177e4SLinus Torvalds 1136eb4698f3STakashi Iwai static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream) 11371da177e4SLinus Torvalds { 1138eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1139eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 1140eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 11411da177e4SLinus Torvalds 1142e560d8d8STakashi Iwai epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); 11431da177e4SLinus Torvalds if (epcm == NULL) 11441da177e4SLinus Torvalds return -ENOMEM; 11451da177e4SLinus Torvalds epcm->emu = emu; 11461da177e4SLinus Torvalds epcm->type = CAPTURE_AC97ADC; 11471da177e4SLinus Torvalds epcm->substream = substream; 11481da177e4SLinus Torvalds epcm->capture_ipr = IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL; 11491da177e4SLinus Torvalds epcm->capture_inte = INTE_ADCBUFENABLE; 11501da177e4SLinus Torvalds epcm->capture_ba_reg = ADCBA; 11511da177e4SLinus Torvalds epcm->capture_bs_reg = ADCBS; 11521da177e4SLinus Torvalds epcm->capture_idx_reg = emu->audigy ? A_ADCIDX : ADCIDX; 11531da177e4SLinus Torvalds runtime->private_data = epcm; 11541da177e4SLinus Torvalds runtime->private_free = snd_emu10k1_pcm_free_substream; 11551da177e4SLinus Torvalds runtime->hw = snd_emu10k1_capture; 11561da177e4SLinus Torvalds emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt; 11571da177e4SLinus Torvalds emu->pcm_capture_substream = substream; 11581da177e4SLinus Torvalds snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); 11591da177e4SLinus Torvalds snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates); 11601da177e4SLinus Torvalds return 0; 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 1163eb4698f3STakashi Iwai static int snd_emu10k1_capture_close(struct snd_pcm_substream *substream) 11641da177e4SLinus Torvalds { 1165eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds emu->capture_interrupt = NULL; 11681da177e4SLinus Torvalds emu->pcm_capture_substream = NULL; 11691da177e4SLinus Torvalds return 0; 11701da177e4SLinus Torvalds } 11711da177e4SLinus Torvalds 1172eb4698f3STakashi Iwai static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream) 11731da177e4SLinus Torvalds { 1174eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1175eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 1176eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 11771da177e4SLinus Torvalds 1178e560d8d8STakashi Iwai epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); 11791da177e4SLinus Torvalds if (epcm == NULL) 11801da177e4SLinus Torvalds return -ENOMEM; 11811da177e4SLinus Torvalds epcm->emu = emu; 11821da177e4SLinus Torvalds epcm->type = CAPTURE_AC97MIC; 11831da177e4SLinus Torvalds epcm->substream = substream; 11841da177e4SLinus Torvalds epcm->capture_ipr = IPR_MICBUFFULL|IPR_MICBUFHALFFULL; 11851da177e4SLinus Torvalds epcm->capture_inte = INTE_MICBUFENABLE; 11861da177e4SLinus Torvalds epcm->capture_ba_reg = MICBA; 11871da177e4SLinus Torvalds epcm->capture_bs_reg = MICBS; 11881da177e4SLinus Torvalds epcm->capture_idx_reg = emu->audigy ? A_MICIDX : MICIDX; 11891da177e4SLinus Torvalds substream->runtime->private_data = epcm; 11901da177e4SLinus Torvalds substream->runtime->private_free = snd_emu10k1_pcm_free_substream; 11911da177e4SLinus Torvalds runtime->hw = snd_emu10k1_capture; 11921da177e4SLinus Torvalds runtime->hw.rates = SNDRV_PCM_RATE_8000; 11931da177e4SLinus Torvalds runtime->hw.rate_min = runtime->hw.rate_max = 8000; 11941da177e4SLinus Torvalds runtime->hw.channels_min = 1; 11951da177e4SLinus Torvalds emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt; 11961da177e4SLinus Torvalds emu->pcm_capture_mic_substream = substream; 11971da177e4SLinus Torvalds snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); 11981da177e4SLinus Torvalds return 0; 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds 1201eb4698f3STakashi Iwai static int snd_emu10k1_capture_mic_close(struct snd_pcm_substream *substream) 12021da177e4SLinus Torvalds { 1203eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 12041da177e4SLinus Torvalds 12051da177e4SLinus Torvalds emu->capture_interrupt = NULL; 12061da177e4SLinus Torvalds emu->pcm_capture_mic_substream = NULL; 12071da177e4SLinus Torvalds return 0; 12081da177e4SLinus Torvalds } 12091da177e4SLinus Torvalds 1210eb4698f3STakashi Iwai static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) 12111da177e4SLinus Torvalds { 1212eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1213eb4698f3STakashi Iwai struct snd_emu10k1_pcm *epcm; 1214eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 12151da177e4SLinus Torvalds int nefx = emu->audigy ? 64 : 32; 12161da177e4SLinus Torvalds int idx; 12171da177e4SLinus Torvalds 1218e560d8d8STakashi Iwai epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); 12191da177e4SLinus Torvalds if (epcm == NULL) 12201da177e4SLinus Torvalds return -ENOMEM; 12211da177e4SLinus Torvalds epcm->emu = emu; 12221da177e4SLinus Torvalds epcm->type = CAPTURE_EFX; 12231da177e4SLinus Torvalds epcm->substream = substream; 12241da177e4SLinus Torvalds epcm->capture_ipr = IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL; 12251da177e4SLinus Torvalds epcm->capture_inte = INTE_EFXBUFENABLE; 12261da177e4SLinus Torvalds epcm->capture_ba_reg = FXBA; 12271da177e4SLinus Torvalds epcm->capture_bs_reg = FXBS; 12281da177e4SLinus Torvalds epcm->capture_idx_reg = FXIDX; 12291da177e4SLinus Torvalds substream->runtime->private_data = epcm; 12301da177e4SLinus Torvalds substream->runtime->private_free = snd_emu10k1_pcm_free_substream; 12319f4bd5ddSJames Courtier-Dutton runtime->hw = snd_emu10k1_capture_efx; 12321da177e4SLinus Torvalds runtime->hw.rates = SNDRV_PCM_RATE_48000; 12331da177e4SLinus Torvalds runtime->hw.rate_min = runtime->hw.rate_max = 48000; 12341da177e4SLinus Torvalds spin_lock_irq(&emu->reg_lock); 12359f4bd5ddSJames Courtier-Dutton if (emu->card_capabilities->emu1010) { 123613d45709SPavel Hofman /* Nb. of channels has been increased to 16 */ 12379f4bd5ddSJames Courtier-Dutton /* TODO 12389f4bd5ddSJames Courtier-Dutton * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE 12399f4bd5ddSJames Courtier-Dutton * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 12409f4bd5ddSJames Courtier-Dutton * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 12419f4bd5ddSJames Courtier-Dutton * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 12429f4bd5ddSJames Courtier-Dutton * rate_min = 44100, 12439f4bd5ddSJames Courtier-Dutton * rate_max = 192000, 124413d45709SPavel Hofman * channels_min = 16, 124513d45709SPavel Hofman * channels_max = 16, 12469f4bd5ddSJames Courtier-Dutton * Need to add mixer control to fix sample rate 12479f4bd5ddSJames Courtier-Dutton * 124813d45709SPavel Hofman * There are 32 mono channels of 16bits each. 12499f4bd5ddSJames Courtier-Dutton * 24bit Audio uses 2x channels over 16bit 12509f4bd5ddSJames Courtier-Dutton * 96kHz uses 2x channels over 48kHz 12519f4bd5ddSJames Courtier-Dutton * 192kHz uses 4x channels over 48kHz 125213d45709SPavel Hofman * So, for 48kHz 24bit, one has 16 channels 125313d45709SPavel Hofman * for 96kHz 24bit, one has 8 channels 125413d45709SPavel Hofman * for 192kHz 24bit, one has 4 channels 125513d45709SPavel Hofman * 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; 1273b0dbdaeaSJames Courtier-Dutton }; 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 13131da177e4SLinus Torvalds emu->capture_interrupt = NULL; 13141da177e4SLinus Torvalds emu->pcm_capture_efx_substream = NULL; 13151da177e4SLinus Torvalds return 0; 13161da177e4SLinus Torvalds } 13171da177e4SLinus Torvalds 1318eb4698f3STakashi Iwai static struct snd_pcm_ops snd_emu10k1_playback_ops = { 13191da177e4SLinus Torvalds .open = snd_emu10k1_playback_open, 13201da177e4SLinus Torvalds .close = snd_emu10k1_playback_close, 13211da177e4SLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 13221da177e4SLinus Torvalds .hw_params = snd_emu10k1_playback_hw_params, 13231da177e4SLinus Torvalds .hw_free = snd_emu10k1_playback_hw_free, 13241da177e4SLinus Torvalds .prepare = snd_emu10k1_playback_prepare, 13251da177e4SLinus Torvalds .trigger = snd_emu10k1_playback_trigger, 13261da177e4SLinus Torvalds .pointer = snd_emu10k1_playback_pointer, 13271da177e4SLinus Torvalds .page = snd_pcm_sgbuf_ops_page, 13281da177e4SLinus Torvalds }; 13291da177e4SLinus Torvalds 1330eb4698f3STakashi Iwai static struct snd_pcm_ops snd_emu10k1_capture_ops = { 13311da177e4SLinus Torvalds .open = snd_emu10k1_capture_open, 13321da177e4SLinus Torvalds .close = snd_emu10k1_capture_close, 13331da177e4SLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 13341da177e4SLinus Torvalds .hw_params = snd_emu10k1_capture_hw_params, 13351da177e4SLinus Torvalds .hw_free = snd_emu10k1_capture_hw_free, 13361da177e4SLinus Torvalds .prepare = snd_emu10k1_capture_prepare, 13371da177e4SLinus Torvalds .trigger = snd_emu10k1_capture_trigger, 13381da177e4SLinus Torvalds .pointer = snd_emu10k1_capture_pointer, 13391da177e4SLinus Torvalds }; 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds /* EFX playback */ 1342eb4698f3STakashi Iwai static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = { 13431da177e4SLinus Torvalds .open = snd_emu10k1_efx_playback_open, 13441da177e4SLinus Torvalds .close = snd_emu10k1_efx_playback_close, 13451da177e4SLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 13461da177e4SLinus Torvalds .hw_params = snd_emu10k1_playback_hw_params, 13471da177e4SLinus Torvalds .hw_free = snd_emu10k1_efx_playback_hw_free, 13481da177e4SLinus Torvalds .prepare = snd_emu10k1_efx_playback_prepare, 13491da177e4SLinus Torvalds .trigger = snd_emu10k1_efx_playback_trigger, 13501da177e4SLinus Torvalds .pointer = snd_emu10k1_efx_playback_pointer, 13511da177e4SLinus Torvalds .page = snd_pcm_sgbuf_ops_page, 13521da177e4SLinus Torvalds }; 13531da177e4SLinus Torvalds 1354eb4698f3STakashi Iwai int __devinit snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) 13551da177e4SLinus Torvalds { 1356eb4698f3STakashi Iwai struct snd_pcm *pcm; 1357eb4698f3STakashi Iwai struct snd_pcm_substream *substream; 13581da177e4SLinus Torvalds int err; 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds if (rpcm) 13611da177e4SLinus Torvalds *rpcm = NULL; 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0) 13641da177e4SLinus Torvalds return err; 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds pcm->private_data = emu; 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_playback_ops); 13691da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_ops); 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds pcm->info_flags = 0; 13721da177e4SLinus Torvalds pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; 13731da177e4SLinus Torvalds strcpy(pcm->name, "ADC Capture/Standard PCM Playback"); 13741da177e4SLinus Torvalds emu->pcm = pcm; 13751da177e4SLinus Torvalds 13761da177e4SLinus Torvalds for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) 13771da177e4SLinus Torvalds if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) 13781da177e4SLinus Torvalds return err; 13791da177e4SLinus Torvalds 13801da177e4SLinus Torvalds for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) 13811da177e4SLinus Torvalds snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); 13821da177e4SLinus Torvalds 13831da177e4SLinus Torvalds if (rpcm) 13841da177e4SLinus Torvalds *rpcm = pcm; 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds return 0; 13871da177e4SLinus Torvalds } 13881da177e4SLinus Torvalds 1389eb4698f3STakashi Iwai int __devinit snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) 13901da177e4SLinus Torvalds { 1391eb4698f3STakashi Iwai struct snd_pcm *pcm; 1392eb4698f3STakashi Iwai struct snd_pcm_substream *substream; 13931da177e4SLinus Torvalds int err; 13941da177e4SLinus Torvalds 13951da177e4SLinus Torvalds if (rpcm) 13961da177e4SLinus Torvalds *rpcm = NULL; 13971da177e4SLinus Torvalds 13981da177e4SLinus Torvalds if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0) 13991da177e4SLinus Torvalds return err; 14001da177e4SLinus Torvalds 14011da177e4SLinus Torvalds pcm->private_data = emu; 14021da177e4SLinus Torvalds 14031da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_efx_playback_ops); 14041da177e4SLinus Torvalds 14051da177e4SLinus Torvalds pcm->info_flags = 0; 14061da177e4SLinus Torvalds pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; 14071da177e4SLinus Torvalds strcpy(pcm->name, "Multichannel Playback"); 140809668b44STakashi Iwai emu->pcm_multi = pcm; 14091da177e4SLinus Torvalds 14101da177e4SLinus Torvalds for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) 14111da177e4SLinus Torvalds if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) 14121da177e4SLinus Torvalds return err; 14131da177e4SLinus Torvalds 14141da177e4SLinus Torvalds if (rpcm) 14151da177e4SLinus Torvalds *rpcm = pcm; 14161da177e4SLinus Torvalds 14171da177e4SLinus Torvalds return 0; 14181da177e4SLinus Torvalds } 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds 1421eb4698f3STakashi Iwai static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = { 14221da177e4SLinus Torvalds .open = snd_emu10k1_capture_mic_open, 14231da177e4SLinus Torvalds .close = snd_emu10k1_capture_mic_close, 14241da177e4SLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 14251da177e4SLinus Torvalds .hw_params = snd_emu10k1_capture_hw_params, 14261da177e4SLinus Torvalds .hw_free = snd_emu10k1_capture_hw_free, 14271da177e4SLinus Torvalds .prepare = snd_emu10k1_capture_prepare, 14281da177e4SLinus Torvalds .trigger = snd_emu10k1_capture_trigger, 14291da177e4SLinus Torvalds .pointer = snd_emu10k1_capture_pointer, 14301da177e4SLinus Torvalds }; 14311da177e4SLinus Torvalds 1432eb4698f3STakashi Iwai int __devinit snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) 14331da177e4SLinus Torvalds { 1434eb4698f3STakashi Iwai struct snd_pcm *pcm; 14351da177e4SLinus Torvalds int err; 14361da177e4SLinus Torvalds 14371da177e4SLinus Torvalds if (rpcm) 14381da177e4SLinus Torvalds *rpcm = NULL; 14391da177e4SLinus Torvalds 14401da177e4SLinus Torvalds if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0) 14411da177e4SLinus Torvalds return err; 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds pcm->private_data = emu; 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops); 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds pcm->info_flags = 0; 14481da177e4SLinus Torvalds strcpy(pcm->name, "Mic Capture"); 14491da177e4SLinus Torvalds emu->pcm_mic = pcm; 14501da177e4SLinus Torvalds 14511da177e4SLinus Torvalds snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds if (rpcm) 14541da177e4SLinus Torvalds *rpcm = pcm; 14551da177e4SLinus Torvalds return 0; 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds 1458eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14591da177e4SLinus Torvalds { 1460eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14611da177e4SLinus Torvalds int nefx = emu->audigy ? 64 : 32; 14621da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 14631da177e4SLinus Torvalds uinfo->count = nefx; 14641da177e4SLinus Torvalds uinfo->value.integer.min = 0; 14651da177e4SLinus Torvalds uinfo->value.integer.max = 1; 14661da177e4SLinus Torvalds return 0; 14671da177e4SLinus Torvalds } 14681da177e4SLinus Torvalds 1469eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 14701da177e4SLinus Torvalds { 1471eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14721da177e4SLinus Torvalds int nefx = emu->audigy ? 64 : 32; 14731da177e4SLinus Torvalds int idx; 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds spin_lock_irq(&emu->reg_lock); 14761da177e4SLinus Torvalds for (idx = 0; idx < nefx; idx++) 14771da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0; 14781da177e4SLinus Torvalds spin_unlock_irq(&emu->reg_lock); 14791da177e4SLinus Torvalds return 0; 14801da177e4SLinus Torvalds } 14811da177e4SLinus Torvalds 1482eb4698f3STakashi Iwai static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 14831da177e4SLinus Torvalds { 1484eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14851da177e4SLinus Torvalds unsigned int nval[2], bits; 14861da177e4SLinus Torvalds int nefx = emu->audigy ? 64 : 32; 14871da177e4SLinus Torvalds int nefxb = emu->audigy ? 7 : 6; 14881da177e4SLinus Torvalds int change, idx; 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds nval[0] = nval[1] = 0; 14911da177e4SLinus Torvalds for (idx = 0, bits = 0; idx < nefx; idx++) 14921da177e4SLinus Torvalds if (ucontrol->value.integer.value[idx]) { 14931da177e4SLinus Torvalds nval[idx / 32] |= 1 << (idx % 32); 14941da177e4SLinus Torvalds bits++; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds for (idx = 0; idx < nefxb; idx++) 14981da177e4SLinus Torvalds if (1 << idx == bits) 14991da177e4SLinus Torvalds break; 15001da177e4SLinus Torvalds 15011da177e4SLinus Torvalds if (idx >= nefxb) 15021da177e4SLinus Torvalds return -EINVAL; 15031da177e4SLinus Torvalds 15041da177e4SLinus Torvalds spin_lock_irq(&emu->reg_lock); 15051da177e4SLinus Torvalds change = (nval[0] != emu->efx_voices_mask[0]) || 15061da177e4SLinus Torvalds (nval[1] != emu->efx_voices_mask[1]); 15071da177e4SLinus Torvalds emu->efx_voices_mask[0] = nval[0]; 15081da177e4SLinus Torvalds emu->efx_voices_mask[1] = nval[1]; 15091da177e4SLinus Torvalds spin_unlock_irq(&emu->reg_lock); 15101da177e4SLinus Torvalds return change; 15111da177e4SLinus Torvalds } 15121da177e4SLinus Torvalds 1513eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = { 15141da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15151da177e4SLinus Torvalds .name = "Captured FX8010 Outputs", 15161da177e4SLinus Torvalds .info = snd_emu10k1_pcm_efx_voices_mask_info, 15171da177e4SLinus Torvalds .get = snd_emu10k1_pcm_efx_voices_mask_get, 15181da177e4SLinus Torvalds .put = snd_emu10k1_pcm_efx_voices_mask_put 15191da177e4SLinus Torvalds }; 15201da177e4SLinus Torvalds 1521eb4698f3STakashi Iwai static struct snd_pcm_ops snd_emu10k1_capture_efx_ops = { 15221da177e4SLinus Torvalds .open = snd_emu10k1_capture_efx_open, 15231da177e4SLinus Torvalds .close = snd_emu10k1_capture_efx_close, 15241da177e4SLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 15251da177e4SLinus Torvalds .hw_params = snd_emu10k1_capture_hw_params, 15261da177e4SLinus Torvalds .hw_free = snd_emu10k1_capture_hw_free, 15271da177e4SLinus Torvalds .prepare = snd_emu10k1_capture_prepare, 15281da177e4SLinus Torvalds .trigger = snd_emu10k1_capture_trigger, 15291da177e4SLinus Torvalds .pointer = snd_emu10k1_capture_pointer, 15301da177e4SLinus Torvalds }; 15311da177e4SLinus Torvalds 15321da177e4SLinus Torvalds 15331da177e4SLinus Torvalds /* EFX playback */ 15341da177e4SLinus Torvalds 15351da177e4SLinus Torvalds #define INITIAL_TRAM_SHIFT 14 15361da177e4SLinus Torvalds #define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1) 15371da177e4SLinus Torvalds 1538eb4698f3STakashi Iwai static void snd_emu10k1_fx8010_playback_irq(struct snd_emu10k1 *emu, void *private_data) 15391da177e4SLinus Torvalds { 1540eb4698f3STakashi Iwai struct snd_pcm_substream *substream = private_data; 15411da177e4SLinus Torvalds snd_pcm_period_elapsed(substream); 15421da177e4SLinus Torvalds } 15431da177e4SLinus Torvalds 15441da177e4SLinus Torvalds static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, 15451da177e4SLinus Torvalds unsigned short *dst_right, 15461da177e4SLinus Torvalds unsigned short *src, 15471da177e4SLinus Torvalds unsigned int count, 15481da177e4SLinus Torvalds unsigned int tram_shift) 15491da177e4SLinus Torvalds { 15509f4bd5ddSJames Courtier-Dutton /* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */ 15511da177e4SLinus Torvalds if ((tram_shift & 1) == 0) { 15521da177e4SLinus Torvalds while (count--) { 15531da177e4SLinus Torvalds *dst_left-- = *src++; 15541da177e4SLinus Torvalds *dst_right-- = *src++; 15551da177e4SLinus Torvalds } 15561da177e4SLinus Torvalds } else { 15571da177e4SLinus Torvalds while (count--) { 15581da177e4SLinus Torvalds *dst_right-- = *src++; 15591da177e4SLinus Torvalds *dst_left-- = *src++; 15601da177e4SLinus Torvalds } 15611da177e4SLinus Torvalds } 15621da177e4SLinus Torvalds } 15631da177e4SLinus Torvalds 1564eb4698f3STakashi Iwai static void fx8010_pb_trans_copy(struct snd_pcm_substream *substream, 1565eb4698f3STakashi Iwai struct snd_pcm_indirect *rec, size_t bytes) 15661da177e4SLinus Torvalds { 1567eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1568eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 15691da177e4SLinus Torvalds unsigned int tram_size = pcm->buffer_size; 15701da177e4SLinus Torvalds unsigned short *src = (unsigned short *)(substream->runtime->dma_area + rec->sw_data); 15711da177e4SLinus Torvalds unsigned int frames = bytes >> 2, count; 15721da177e4SLinus Torvalds unsigned int tram_pos = pcm->tram_pos; 15731da177e4SLinus Torvalds unsigned int tram_shift = pcm->tram_shift; 15741da177e4SLinus Torvalds 15751da177e4SLinus Torvalds while (frames > tram_pos) { 15761da177e4SLinus Torvalds count = tram_pos + 1; 15771da177e4SLinus Torvalds snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos, 15781da177e4SLinus Torvalds (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2, 15791da177e4SLinus Torvalds src, count, tram_shift); 15801da177e4SLinus Torvalds src += count * 2; 15811da177e4SLinus Torvalds frames -= count; 15821da177e4SLinus Torvalds tram_pos = (tram_size / 2) - 1; 15831da177e4SLinus Torvalds tram_shift++; 15841da177e4SLinus Torvalds } 15851da177e4SLinus Torvalds snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos, 15861da177e4SLinus Torvalds (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2, 15871da177e4SLinus Torvalds src, frames, tram_shift); 15881da177e4SLinus Torvalds tram_pos -= frames; 15891da177e4SLinus Torvalds pcm->tram_pos = tram_pos; 15901da177e4SLinus Torvalds pcm->tram_shift = tram_shift; 15911da177e4SLinus Torvalds } 15921da177e4SLinus Torvalds 1593eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_transfer(struct snd_pcm_substream *substream) 15941da177e4SLinus Torvalds { 1595eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1596eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 15971da177e4SLinus Torvalds 15981da177e4SLinus Torvalds snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec, fx8010_pb_trans_copy); 15991da177e4SLinus Torvalds return 0; 16001da177e4SLinus Torvalds } 16011da177e4SLinus Torvalds 1602eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_hw_params(struct snd_pcm_substream *substream, 1603eb4698f3STakashi Iwai struct snd_pcm_hw_params *hw_params) 16041da177e4SLinus Torvalds { 16051da177e4SLinus Torvalds return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); 16061da177e4SLinus Torvalds } 16071da177e4SLinus Torvalds 1608eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_hw_free(struct snd_pcm_substream *substream) 16091da177e4SLinus Torvalds { 1610eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1611eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 16121da177e4SLinus Torvalds unsigned int i; 16131da177e4SLinus Torvalds 16141da177e4SLinus Torvalds for (i = 0; i < pcm->channels; i++) 16151da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, 0); 16161da177e4SLinus Torvalds snd_pcm_lib_free_pages(substream); 16171da177e4SLinus Torvalds return 0; 16181da177e4SLinus Torvalds } 16191da177e4SLinus Torvalds 1620eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substream) 16211da177e4SLinus Torvalds { 1622eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1623eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 1624eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 16251da177e4SLinus Torvalds unsigned int i; 16261da177e4SLinus Torvalds 16279f4bd5ddSJames Courtier-Dutton /* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */ 16281da177e4SLinus Torvalds memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec)); 16291da177e4SLinus Torvalds pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */ 16301da177e4SLinus Torvalds pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); 16311da177e4SLinus Torvalds pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); 16321da177e4SLinus Torvalds pcm->tram_shift = 0; 16331da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_running, 0, 0); /* reset */ 16341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); /* reset */ 16351da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_size, 0, runtime->buffer_size); 16361da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_ptr, 0, 0); /* reset ptr number */ 16371da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_count, 0, runtime->period_size); 16381da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_tmpcount, 0, runtime->period_size); 16391da177e4SLinus Torvalds for (i = 0; i < pcm->channels; i++) 16401da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels)); 16411da177e4SLinus Torvalds return 0; 16421da177e4SLinus Torvalds } 16431da177e4SLinus Torvalds 1644eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substream, int cmd) 16451da177e4SLinus Torvalds { 1646eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1647eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 16481da177e4SLinus Torvalds int result = 0; 16491da177e4SLinus Torvalds 16501da177e4SLinus Torvalds spin_lock(&emu->reg_lock); 16511da177e4SLinus Torvalds switch (cmd) { 16521da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_START: 16531da177e4SLinus Torvalds /* follow thru */ 16541da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 165509668b44STakashi Iwai case SNDRV_PCM_TRIGGER_RESUME: 16561da177e4SLinus Torvalds #ifdef EMU10K1_SET_AC3_IEC958 16571da177e4SLinus Torvalds { 16581da177e4SLinus Torvalds int i; 16591da177e4SLinus Torvalds for (i = 0; i < 3; i++) { 16601da177e4SLinus Torvalds unsigned int bits; 16611da177e4SLinus Torvalds bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | 16621da177e4SLinus Torvalds SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 16631da177e4SLinus Torvalds 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA; 16641da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + i, 0, bits); 16651da177e4SLinus Torvalds } 16661da177e4SLinus Torvalds } 16671da177e4SLinus Torvalds #endif 16681da177e4SLinus Torvalds result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq); 16691da177e4SLinus Torvalds if (result < 0) 16701da177e4SLinus Torvalds goto __err; 16711da177e4SLinus Torvalds snd_emu10k1_fx8010_playback_transfer(substream); /* roll the ball */ 16721da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1); 16731da177e4SLinus Torvalds break; 16741da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_STOP: 16751da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 167609668b44STakashi Iwai case SNDRV_PCM_TRIGGER_SUSPEND: 16771da177e4SLinus Torvalds snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL; 16781da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); 16791da177e4SLinus Torvalds pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); 16801da177e4SLinus Torvalds pcm->tram_shift = 0; 16811da177e4SLinus Torvalds break; 16821da177e4SLinus Torvalds default: 16831da177e4SLinus Torvalds result = -EINVAL; 16841da177e4SLinus Torvalds break; 16851da177e4SLinus Torvalds } 16861da177e4SLinus Torvalds __err: 16871da177e4SLinus Torvalds spin_unlock(&emu->reg_lock); 16881da177e4SLinus Torvalds return result; 16891da177e4SLinus Torvalds } 16901da177e4SLinus Torvalds 1691eb4698f3STakashi Iwai static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(struct snd_pcm_substream *substream) 16921da177e4SLinus Torvalds { 1693eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1694eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 16951da177e4SLinus Torvalds size_t ptr; /* byte pointer */ 16961da177e4SLinus Torvalds 16971da177e4SLinus Torvalds if (!snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_trigger, 0)) 16981da177e4SLinus Torvalds return 0; 16991da177e4SLinus Torvalds ptr = snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_ptr, 0) << 2; 17001da177e4SLinus Torvalds return snd_pcm_indirect_playback_pointer(substream, &pcm->pcm_rec, ptr); 17011da177e4SLinus Torvalds } 17021da177e4SLinus Torvalds 1703eb4698f3STakashi Iwai static struct snd_pcm_hardware snd_emu10k1_fx8010_playback = 17041da177e4SLinus Torvalds { 17051da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 170609668b44STakashi Iwai SNDRV_PCM_INFO_RESUME | 17071da177e4SLinus Torvalds /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), 17081da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 17091da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_48000, 17101da177e4SLinus Torvalds .rate_min = 48000, 17111da177e4SLinus Torvalds .rate_max = 48000, 17121da177e4SLinus Torvalds .channels_min = 1, 17131da177e4SLinus Torvalds .channels_max = 1, 17141da177e4SLinus Torvalds .buffer_bytes_max = (128*1024), 17151da177e4SLinus Torvalds .period_bytes_min = 1024, 17161da177e4SLinus Torvalds .period_bytes_max = (128*1024), 17171da177e4SLinus Torvalds .periods_min = 1, 17181da177e4SLinus Torvalds .periods_max = 1024, 17191da177e4SLinus Torvalds .fifo_size = 0, 17201da177e4SLinus Torvalds }; 17211da177e4SLinus Torvalds 1722eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_open(struct snd_pcm_substream *substream) 17231da177e4SLinus Torvalds { 1724eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1725eb4698f3STakashi Iwai struct snd_pcm_runtime *runtime = substream->runtime; 1726eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 17271da177e4SLinus Torvalds 17281da177e4SLinus Torvalds runtime->hw = snd_emu10k1_fx8010_playback; 17291da177e4SLinus Torvalds runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels; 17301da177e4SLinus Torvalds runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2; 17311da177e4SLinus Torvalds spin_lock_irq(&emu->reg_lock); 17321da177e4SLinus Torvalds if (pcm->valid == 0) { 17331da177e4SLinus Torvalds spin_unlock_irq(&emu->reg_lock); 17341da177e4SLinus Torvalds return -ENODEV; 17351da177e4SLinus Torvalds } 17361da177e4SLinus Torvalds pcm->opened = 1; 17371da177e4SLinus Torvalds spin_unlock_irq(&emu->reg_lock); 17381da177e4SLinus Torvalds return 0; 17391da177e4SLinus Torvalds } 17401da177e4SLinus Torvalds 1741eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_playback_close(struct snd_pcm_substream *substream) 17421da177e4SLinus Torvalds { 1743eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); 1744eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; 17451da177e4SLinus Torvalds 17461da177e4SLinus Torvalds spin_lock_irq(&emu->reg_lock); 17471da177e4SLinus Torvalds pcm->opened = 0; 17481da177e4SLinus Torvalds spin_unlock_irq(&emu->reg_lock); 17491da177e4SLinus Torvalds return 0; 17501da177e4SLinus Torvalds } 17511da177e4SLinus Torvalds 1752eb4698f3STakashi Iwai static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = { 17531da177e4SLinus Torvalds .open = snd_emu10k1_fx8010_playback_open, 17541da177e4SLinus Torvalds .close = snd_emu10k1_fx8010_playback_close, 17551da177e4SLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 17561da177e4SLinus Torvalds .hw_params = snd_emu10k1_fx8010_playback_hw_params, 17571da177e4SLinus Torvalds .hw_free = snd_emu10k1_fx8010_playback_hw_free, 17581da177e4SLinus Torvalds .prepare = snd_emu10k1_fx8010_playback_prepare, 17591da177e4SLinus Torvalds .trigger = snd_emu10k1_fx8010_playback_trigger, 17601da177e4SLinus Torvalds .pointer = snd_emu10k1_fx8010_playback_pointer, 17611da177e4SLinus Torvalds .ack = snd_emu10k1_fx8010_playback_transfer, 17621da177e4SLinus Torvalds }; 17631da177e4SLinus Torvalds 1764eb4698f3STakashi Iwai int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) 17651da177e4SLinus Torvalds { 1766eb4698f3STakashi Iwai struct snd_pcm *pcm; 1767eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 17681da177e4SLinus Torvalds int err; 17691da177e4SLinus Torvalds 17701da177e4SLinus Torvalds if (rpcm) 17711da177e4SLinus Torvalds *rpcm = NULL; 17721da177e4SLinus Torvalds 17731da177e4SLinus Torvalds if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0) 17741da177e4SLinus Torvalds return err; 17751da177e4SLinus Torvalds 17761da177e4SLinus Torvalds pcm->private_data = emu; 17771da177e4SLinus Torvalds 17781da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops); 17791da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops); 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvalds pcm->info_flags = 0; 17821da177e4SLinus Torvalds strcpy(pcm->name, "Multichannel Capture/PT Playback"); 17831da177e4SLinus Torvalds emu->pcm_efx = pcm; 17841da177e4SLinus Torvalds if (rpcm) 17851da177e4SLinus Torvalds *rpcm = pcm; 17861da177e4SLinus Torvalds 17871da177e4SLinus Torvalds /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs 17881da177e4SLinus Torvalds * to these 17891da177e4SLinus Torvalds */ 17901da177e4SLinus Torvalds 17911da177e4SLinus Torvalds /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ 17921da177e4SLinus Torvalds if (emu->audigy) { 17931da177e4SLinus Torvalds emu->efx_voices_mask[0] = 0; 179413d45709SPavel Hofman if (emu->card_capabilities->emu1010) 179513d45709SPavel Hofman /* Pavel Hofman - 32 voices will be used for 179613d45709SPavel Hofman * capture (write mode) - 179713d45709SPavel Hofman * each bit = corresponding voice 179813d45709SPavel Hofman */ 179913d45709SPavel Hofman emu->efx_voices_mask[1] = 0xffffffff; 180013d45709SPavel Hofman else 18011da177e4SLinus Torvalds emu->efx_voices_mask[1] = 0xffff; 18021da177e4SLinus Torvalds } else { 18031da177e4SLinus Torvalds emu->efx_voices_mask[0] = 0xffff0000; 18041da177e4SLinus Torvalds emu->efx_voices_mask[1] = 0; 18051da177e4SLinus Torvalds } 180613d45709SPavel Hofman /* For emu1010, the control has to set 32 upper bits (voices) 180713d45709SPavel Hofman * out of the 64 bits (voices) to true for the 16-channels capture 180813d45709SPavel Hofman * to work correctly. Correct A_FXWC2 initial value (0xffffffff) 180913d45709SPavel Hofman * is already defined but the snd_emu10k1_pcm_efx_voices_mask 181013d45709SPavel Hofman * control can override this register's value. 181113d45709SPavel Hofman */ 181267ed4161SClemens Ladisch kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu); 181367ed4161SClemens Ladisch if (!kctl) 181467ed4161SClemens Ladisch return -ENOMEM; 181567ed4161SClemens Ladisch kctl->id.device = device; 181667ed4161SClemens Ladisch snd_ctl_add(emu->card, kctl); 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); 18191da177e4SLinus Torvalds 18201da177e4SLinus Torvalds return 0; 18211da177e4SLinus Torvalds } 1822