From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S268602AbTGOPor (ORCPT ); Tue, 15 Jul 2003 11:44:47 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S268586AbTGOPor (ORCPT ); Tue, 15 Jul 2003 11:44:47 -0400 Received: from ss1000.ms.mff.cuni.cz ([195.113.19.221]:50122 "EHLO ss1000.ms.mff.cuni.cz") by vger.kernel.org with ESMTP id S268602AbTGOPiM (ORCPT ); Tue, 15 Jul 2003 11:38:12 -0400 Date: Tue, 15 Jul 2003 17:53:00 +0200 From: Rudo Thomas To: linux-kernel@vger.kernel.org Subject: [PATCH][RFC] update emu10k1 to the latest CVS (and more) Message-ID: <20030715175258.B18899@ss1000.ms.mff.cuni.cz> Mail-Followup-To: linux-kernel@vger.kernel.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="IiVenqGWf+H9Y6IX" Content-Disposition: inline User-Agent: Mutt/1.2.5.1i Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org --IiVenqGWf+H9Y6IX Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi there. As the current emu10k1 oss code does not play well with the latest userland tools (available from http://sourceforge.net/projects/emu10k1/), I decided to make a patch that does the following: * updates the code to the latest CVS (ported to the new AC97 API) - this makes emu-script and friends happy again * delays registering sound devices until after initialization as suggested by Alan Cox in a #warning in sound/oss/emu10k1/main.c * fixes oops when the module is being removed (see my other patch) * changes char s[32] to s[48] as suggested a few days ago by Laurent Canet Any comments appreciated. Thanks. Rudo. --IiVenqGWf+H9Y6IX Content-Type: text/plain; charset=us-ascii Content-Disposition: inline; filename="emu10k1-0.20a-2.6.0-test1.patch" diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/8010.h linux-2.6.0-test1/sound/oss/emu10k1/8010.h --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/8010.h 2003-07-14 05:28:56.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/8010.h 2003-07-15 03:11:58.000000000 +0200 @@ -1,7 +1,7 @@ /* ********************************************************************** * 8010.h - * Copyright 1999, 2000 Creative Labs, Inc. + * Copyright 1999-2001 Creative Labs, Inc. * ********************************************************************** * @@ -11,6 +11,8 @@ * November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS * line endings * December 8, 1999 Jon Taylor Added lots of new register info + * May 16, 2001 Daniel Bertrand Added unofficial DBG register info + * Oct-Nov 2001 D.B. Added unofficial Audigy registers * ********************************************************************** * @@ -39,6 +41,14 @@ #include +// Driver version: +#define MAJOR_VER 0 +#define MINOR_VER 20 +#define DRIVER_VERSION "0.20a" + + +// Audigy specify registers are prefixed with 'A_' + /************************************************************************************************/ /* PCI function 0 registers, address = + PCIBASE0 */ /************************************************************************************************/ @@ -57,6 +67,11 @@ #define IPR 0x08 /* Global interrupt pending register */ /* Clear pending interrupts by writing a 1 to */ /* the relevant bits and zero to the other bits */ + +/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */ +#define A_IPR_MIDITRANSBUFEMPTY2 0x10000000 /* MIDI UART transmit buffer empty */ +#define A_IPR_MIDIRECVBUFEMPTY2 0x08000000 /* MIDI UART receive buffer empty */ + #define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */ #define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */ #define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */ @@ -81,6 +96,10 @@ /* IP is written with CL set, the bit in CLIPL */ /* or CLIPH corresponding to the CIN value */ /* written will be cleared. */ +#define A_IPR_MIDITRANSBUFEMPTY1 IPR_MIDITRANSBUFEMPTY /* MIDI UART transmit buffer empty */ +#define A_IPR_MIDIRECVBUFEMPTY1 IPR_MIDIRECVBUFEMPTY /* MIDI UART receive buffer empty */ + + #define INTE 0x0c /* Interrupt enable register */ #define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */ @@ -108,6 +127,11 @@ /* behavior and possibly random segfaults and */ /* lockups if enabled. */ +/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */ +#define A_INTE_MIDITXENABLE2 0x00020000 /* Enable MIDI transmit-buffer-empty interrupts */ +#define A_INTE_MIDIRXENABLE2 0x00010000 /* Enable MIDI receive-buffer-empty interrupts */ + + #define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */ /* NOTE: This bit must always be enabled */ #define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */ @@ -124,6 +148,10 @@ #define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */ #define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */ +/* The next two interrupts are for the midi port on the Audigy (A_MPU2) */ +#define A_INTE_MIDITXENABLE1 INTE_MIDITXENABLE +#define A_INTE_MIDIRXENABLE1 INTE_MIDIRXENABLE + #define WC 0x10 /* Wall Clock register */ #define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */ #define WC_SAMPLECOUNTER 0x14060010 @@ -186,6 +214,8 @@ /* Should be set to 1 when the EMU10K1 is */ /* completely initialized. */ +//For Audigy, MPU port move to 0x70-0x74 ptr register + #define MUDATA 0x18 /* MPU401 data register (8 bits) */ #define MUCMD 0x19 /* MPU401 command register (8 bits) */ @@ -197,13 +227,16 @@ #define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */ #define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */ -#define TIMER 0x1a /* Timer terminal count register */ +#define A_IOCFG 0x18 /* GPIO on Audigy card (16bits) */ +#define A_GPINPUT_MASK 0xff00 +#define A_GPOUTPUT_MASK 0x00ff + +#define TIMER 0x1a /* Timer terminal count register (16-bit) */ /* NOTE: After the rate is changed, a maximum */ /* of 1024 sample periods should be allowed */ /* before the new rate is guaranteed accurate. */ -#define TIMER_RATE_MASK 0x000003ff /* Timer interrupt rate in sample periods */ +#define TIMER_RATE_MASK 0x03ff /* Timer interrupt rate in sample periods */ /* 0 == 1024 periods, [1..4] are not useful */ -#define TIMER_RATE 0x0a00001a #define AC97DATA 0x1c /* AC97 register set data register (16 bit) */ @@ -386,6 +419,8 @@ #define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */ #define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */ /* Signed 2's complement, with +/- 12dB extremes */ +#define TREMFRQ_FREQUENCY 0x000000ff /* Tremolo LFO frequency */ + /* ??Hz steps, maximum of ?? Hz. */ #define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */ #define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */ @@ -426,7 +461,12 @@ #define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */ /* NOTE: To guarantee phase coherency, both channels */ /* must be disabled prior to enabling both channels. */ +#define A_ADCCR_RCHANENABLE 0x00000020 +#define A_ADCCR_LCHANENABLE 0x00000010 + +#define A_ADCCR_SAMPLERATE_MASK 0x0000000F /* Audigy sample rate convertor output rate */ #define ADCCR_SAMPLERATE_MASK 0x00000007 /* Sample rate convertor output rate */ + #define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */ #define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */ #define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */ @@ -436,10 +476,16 @@ #define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */ #define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz sample rate */ +#define A_ADCCR_SAMPLERATE_12 0x00000006 /* 12kHz sample rate */ +#define A_ADCCR_SAMPLERATE_11 0x00000007 /* 11.025kHz sample rate */ +#define A_ADCCR_SAMPLERATE_8 0x00000008 /* 8kHz sample rate */ + #define FXWC 0x43 /* FX output write channels register */ /* When set, each bit enables the writing of the */ - /* corresponding FX output channel into host memory */ - + /* corresponding FX output channel (internal registers */ + /* 0x20-0x3f) into host memory. This mode of recording */ + /* is 16bit, 48KHz only. All 32 channels can be enabled */ + /* simultaneously. */ #define TCBS 0x44 /* Tank cache buffer size register */ #define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ #define TCBS_BUFFSIZE_16K 0x00000000 @@ -519,6 +565,13 @@ #define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ +#define A_DBG 0x53 +#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */ +#define A_DBG_ZC 0x40000000 /* zero tram counter */ +#define A_DBG_STEP_ADDR 0x000003ff +#define A_DBG_SATURATION_OCCURED 0x20000000 +#define A_DBG_SATURATION_ADDR 0x0ffc0000 + #define SPCS0 0x54 /* SPDIF output Channel Status 0 register */ #define SPCS1 0x55 /* SPDIF output Channel Status 1 register */ @@ -582,10 +635,19 @@ #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ #define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ + +/* Note that these values can vary +/- by a small amount */ +#define SRCS_SPDIFRATE_44 0x0003acd9 +#define SRCS_SPDIFRATE_48 0x00040000 +#define SRCS_SPDIFRATE_96 0x00080000 + #define MICIDX 0x63 /* Microphone recording buffer index register */ #define MICIDX_MASK 0x0000ffff /* 16-bit value */ #define MICIDX_IDX 0x10000063 +#define A_ADCIDX 0x63 +#define A_ADCIDX_IDX 0x10000063 + #define ADCIDX 0x64 /* ADC recording buffer index register */ #define ADCIDX_MASK 0x0000ffff /* 16 bit index field */ #define ADCIDX_IDX 0x10000064 @@ -594,9 +656,50 @@ #define FXIDX_MASK 0x0000ffff /* 16-bit value */ #define FXIDX_IDX 0x10000065 +/* This is the MPU port on the card (via the game port) */ +#define A_MUDATA1 0x70 +#define A_MUCMD1 0x71 +#define A_MUSTAT1 A_MUCMD1 + +/* This is the MPU port on the Audigy Drive */ +#define A_MUDATA2 0x72 +#define A_MUCMD2 0x73 +#define A_MUSTAT2 A_MUCMD2 + +/* The next two are the Audigy equivalent of FXWC */ +/* the Audigy can record any output (16bit, 48kHz, up to 64 channel simultaneously) */ +/* Each bit selects a channel for recording */ +#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */ +#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ + +#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ +#define A_SPDIF_48000 0x00000080 +#define A_SPDIF_44100 0x00000000 +#define A_SPDIF_96000 0x00000040 + +#define A_FXRT2 0x7c +#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ +#define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */ +#define A_FXRT_CHANNELG 0x003f0000 /* Effects send bus number for channel's effects send G */ +#define A_FXRT_CHANNELH 0x3f000000 /* Effects send bus number for channel's effects send H */ + +#define A_SENDAMOUNTS 0x7d +#define A_FXSENDAMOUNT_E_MASK 0xff000000 +#define A_FXSENDAMOUNT_F_MASK 0x00ff0000 +#define A_FXSENDAMOUNT_G_MASK 0x0000ff00 +#define A_FXSENDAMOUNT_H_MASK 0x000000ff + +/* The send amounts for this one are the same as used with the emu10k1 */ +#define A_FXRT1 0x7e +#define A_FXRT_CHANNELA 0x0000003f +#define A_FXRT_CHANNELB 0x00003f00 +#define A_FXRT_CHANNELC 0x003f0000 +#define A_FXRT_CHANNELD 0x3f000000 + + /* Each FX general purpose register is 32 bits in length, all bits are used */ #define FXGPREGBASE 0x100 /* FX general purpose registers base */ - +#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */ /* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */ /* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */ /* locations are for external TRAM. */ @@ -621,4 +724,14 @@ #define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */ #define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */ + +/* Audigy Soundcard have a different instruction format */ +#define AUDIGY_CODEBASE 0x600 +#define A_LOWORD_OPY_MASK 0x000007ff +#define A_LOWORD_OPX_MASK 0x007ff000 +#define A_HIWORD_OPCODE_MASK 0x0f000000 +#define A_HIWORD_RESULT_MASK 0x007ff000 +#define A_HIWORD_OPA_MASK 0x000007ff + + #endif /* _8010_H */ diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/audio.c linux-2.6.0-test1/sound/oss/emu10k1/audio.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/audio.c 2003-07-14 05:30:38.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/audio.c 2003-07-15 03:11:58.000000000 +0200 @@ -158,8 +158,8 @@ spin_unlock_irqrestore(&woinst->lock, flags); return -ENXIO; } - - if (woinst->format.passthrough) { + // This is for emu10k1 revs less than 7, we need to go through tram + if (woinst->format.passthrough == 1) { int r; woinst->buffer.ossfragshift = PT_BLOCKSIZE_LOG2; @@ -350,8 +350,9 @@ case SNDCTL_DSP_GETCAPS: DPF(2, "SNDCTL_DSP_GETCAPS:\n"); - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg); - + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | + DSP_CAP_TRIGGER | DSP_CAP_MMAP | + DSP_CAP_COPROC| DSP_CAP_MULTI, (int *) arg); case SNDCTL_DSP_SPEED: DPF(2, "SNDCTL_DSP_SPEED:\n"); @@ -528,8 +529,8 @@ else if (file->f_mode & FMODE_WRITE) { val = AFMT_S16_LE | AFMT_U8; if (emu10k1_find_control_gpr(&wave_dev->card->mgr, - wave_dev->card->pt.patch_name, - wave_dev->card->pt.enable_gpr_name) >= 0) + wave_dev->card->pt.patch_name, + wave_dev->card->pt.enable_gpr_name) >= 0) val |= AFMT_AC3; } return put_user(val, (int *) arg); @@ -789,7 +790,7 @@ cinfo.blocks = 0; } - if(wiinst->mmapped) + if (wiinst->mmapped) wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size; spin_unlock_irqrestore(&wiinst->lock, flags); @@ -811,15 +812,17 @@ spin_lock_irqsave(&woinst->lock, flags); if (woinst->state & WAVE_STATE_OPEN || - (woinst->format.passthrough && wave_dev->card->pt.state)) { + ((woinst->format.passthrough == 1) && wave_dev->card->pt.state)) { int num_fragments; - if (woinst->format.passthrough) { + + if (woinst->format.passthrough == 1) { emu10k1_pt_waveout_update(wave_dev); cinfo.bytes = woinst->total_played; } else { emu10k1_waveout_update(woinst); cinfo.bytes = woinst->total_played; } + cinfo.ptr = woinst->buffer.hw_pos; num_fragments = cinfo.bytes / woinst->buffer.fragment_size; cinfo.blocks = num_fragments - woinst->blocks; @@ -899,7 +902,7 @@ if (file->f_mode & FMODE_WRITE) { /* digital pass-through fragment count and size are fixed values */ - if (woinst->state & WAVE_STATE_OPEN || woinst->format.passthrough) + if (woinst->state & WAVE_STATE_OPEN || (woinst->format.passthrough == 1)) return -EINVAL; /* too late to change */ woinst->buffer.ossfragshift = val & 0xffff; @@ -936,19 +939,35 @@ kfree (buf); return -EINVAL; } + + if (buf->command == CMD_WRITE) { + #ifdef DBGEMU - if ( (buf->offs < 0) || (buf->offs + buf->len > 0x800) || (buf->len > 1000)) { + if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) { #else - if ( ((buf->offs < 0x100 ) || (buf->offs + buf->len > 0x800) || (buf->len > 1000)) - && !( ( buf->offs == DBG) && (buf->len ==1) )){ -#endif - kfree(buf); - return -EINVAL; - } + if (((buf->offs < 0x100) || (buf->offs + buf->len > (wave_dev->card->is_audigy ? 0xe00 : 0x800)) || (buf->len > 1000) + ) && !( + //any register allowed raw access to users goes here: + (buf->offs == DBG || + buf->offs == A_DBG) + && (buf->len == 1))) { +#endif + kfree(buf); + return -EINVAL; + } + } else { + if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) { + kfree(buf); + return -EINVAL; + } + } + + if (((unsigned)buf->flags) > 0x3f) + buf->flags = 0; if (buf->command == CMD_READ) { for (i = 0; i < buf->len; i++) - ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, 0); + ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, buf->flags); if (copy_to_user((copr_buffer *) arg, buf, sizeof(copr_buffer))) { kfree(buf); @@ -956,7 +975,7 @@ } } else { for (i = 0; i < buf->len; i++) - sblive_writeptr(wave_dev->card, buf->offs + i, 0, ((u32 *) buf->data)[i]); + sblive_writeptr(wave_dev->card, buf->offs + i, buf->flags, ((u32 *) buf->data)[i]); } kfree (buf); @@ -1244,8 +1263,9 @@ struct woinst *woinst = wave_dev->woinst; spin_lock_irqsave(&woinst->lock, flags); - - if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE) { + if(woinst->format.passthrough==2) + card->pt.state=PT_STATE_PLAYING; + if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE){ spin_lock(&card->pt.lock); emu10k1_pt_stop(card); spin_unlock(&card->pt.lock); diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/cardmi.c linux-2.6.0-test1/sound/oss/emu10k1/cardmi.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/cardmi.c 2003-07-14 05:34:33.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/cardmi.c 2003-07-15 03:11:58.000000000 +0200 @@ -113,7 +113,7 @@ } /* Disable RX interrupt */ - emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE); emu10k1_mpu_release(card); @@ -189,7 +189,7 @@ card_mpuin->qhead = 0; card_mpuin->qtail = 0; - emu10k1_irq_enable(card, INTE_MIDIRXENABLE); + emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE); } return 0; @@ -207,7 +207,7 @@ DPF(2, "emu10k1_mpuin_stop()\n"); - emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE); card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ @@ -246,7 +246,7 @@ DPF(2, "emu10k1_mpuin_reset()\n"); - emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE); while (card_mpuin->firstmidiq) { midiq = card_mpuin->firstmidiq; diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/cardmo.c linux-2.6.0-test1/sound/oss/emu10k1/cardmo.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/cardmo.c 2003-07-14 05:30:43.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/cardmo.c 2003-07-15 03:11:58.000000000 +0200 @@ -72,7 +72,7 @@ DPF(2, "emu10k1_mpuout_close()\n"); - emu10k1_irq_disable(card, INTE_MIDITXENABLE); + emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); spin_lock_irqsave(&card_mpuout->lock, flags); @@ -142,7 +142,7 @@ card_mpuout->intr = 0; - emu10k1_irq_enable(card, INTE_MIDITXENABLE); + emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); spin_unlock_irqrestore(&card_mpuout->lock, flags); @@ -206,7 +206,7 @@ if ((card_mpuout->firstmidiq != NULL) || cByteSent) { card_mpuout->intr = 0; - emu10k1_irq_enable(card, INTE_MIDITXENABLE); + emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); } spin_unlock_irqrestore(&card_mpuout->lock, flags); @@ -221,7 +221,7 @@ DPF(4, "emu10k1_mpuout_irqhandler\n"); card_mpuout->intr = 1; - emu10k1_irq_disable(card, INTE_MIDITXENABLE); + emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); tasklet_hi_schedule(&card_mpuout->tasklet); diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/cardwo.c linux-2.6.0-test1/sound/oss/emu10k1/cardwo.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/cardwo.c 2003-07-14 05:37:17.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/cardwo.c 2003-07-15 03:11:58.000000000 +0200 @@ -85,25 +85,36 @@ break; } if (do_passthrough) { - i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name); - j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name); /* currently only one waveout instance may use pass-through */ - if (i < 0 || j < 0 || woinst->state != WAVE_STATE_CLOSED || + if (woinst->state != WAVE_STATE_CLOSED || card->pt.state != PT_STATE_INACTIVE || - (wave_fmt->samplingrate != 48000 && !is_ac3) || (wave_fmt->samplingrate != 48000 && !is_ac3)) { DPF(2, "unable to set pass-through mode\n"); - } else { - wave_fmt->samplingrate = 48000; - wave_fmt->channels = 2; - wave_fmt->passthrough = 1; - card->pt.intr_gpr = i; - card->pt.enable_gpr = j; - card->pt.state = PT_STATE_INACTIVE; - card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.pos_gpr_name); - DPD(2, "is_ac3 is %d\n", is_ac3); - card->pt.ac3data = is_ac3; - wave_fmt->bitsperchannel = 16; + } else if (USE_PT_METHOD1) { + i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name); + j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name); + if (i < 0 || j < 0) + DPF(2, "unable to set pass-through mode\n"); + else { + wave_fmt->samplingrate = 48000; + wave_fmt->channels = 2; + card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, + card->pt.pos_gpr_name); + wave_fmt->passthrough = 1; + card->pt.intr_gpr = i; + card->pt.enable_gpr = j; + card->pt.state = PT_STATE_INACTIVE; + + DPD(2, "is_ac3 is %d\n", is_ac3); + card->pt.ac3data = is_ac3; + wave_fmt->bitsperchannel = 16; + } + }else{ + DPF(2, "Using Passthrough Method 2\n"); + card->pt.enable_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, + card->pt.enable_gpr_name); + wave_fmt->passthrough = 2; + wave_fmt->bitsperchannel = 16; } } @@ -149,33 +160,37 @@ voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample; voice->start = voice->startloop; - if (voice->flags & VOICE_FLAGS_STEREO) { - voice->params[0].send_a = card->waveout.send_a[1]; - voice->params[0].send_b = card->waveout.send_b[1]; - voice->params[0].send_c = card->waveout.send_c[1]; - voice->params[0].send_d = card->waveout.send_d[1]; - - if (woinst->device) - voice->params[0].send_routing = 0x7654; - else - voice->params[0].send_routing = card->waveout.send_routing[1]; - - voice->params[0].volume_target = 0xffff; - voice->params[0].initial_fc = 0xff; - voice->params[0].initial_attn = 0x00; - voice->params[0].byampl_env_sustain = 0x7f; - voice->params[0].byampl_env_decay = 0x7f; - - voice->params[1].send_a = card->waveout.send_a[2]; - voice->params[1].send_b = card->waveout.send_b[2]; - voice->params[1].send_c = card->waveout.send_c[2]; - voice->params[1].send_d = card->waveout.send_d[2]; - - if (woinst->device) - voice->params[1].send_routing = 0x7654; - else - voice->params[1].send_routing = card->waveout.send_routing[2]; + + voice->params[0].volume_target = 0xffff; + voice->params[0].initial_fc = 0xff; + voice->params[0].initial_attn = 0x00; + voice->params[0].byampl_env_sustain = 0x7f; + voice->params[0].byampl_env_decay = 0x7f; + + if (voice->flags & VOICE_FLAGS_STEREO) { + if (woinst->format.passthrough == 2) { + voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PT]; + voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PT]; + voice->params[0].send_dcba = 0xff; + voice->params[1].send_dcba = 0xff00; + voice->params[0].send_hgfe = voice->params[1].send_hgfe=0; + } else { + voice->params[0].send_dcba = card->waveout.send_dcba[SEND_LEFT]; + voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_LEFT]; + voice->params[1].send_dcba = card->waveout.send_dcba[SEND_RIGHT]; + voice->params[1].send_hgfe = card->waveout.send_hgfe[SEND_RIGHT]; + + if (woinst->device) { + // /dev/dps1 + voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM1]; + voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1]; + } else { + voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM]; + voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM]; + } + } + voice->params[1].volume_target = 0xffff; voice->params[1].initial_fc = 0xff; voice->params[1].initial_attn = 0x00; @@ -183,30 +198,28 @@ voice->params[1].byampl_env_decay = 0x7f; } else { if (woinst->num_voices > 1) { - voice->params[0].send_a = 0xff; - voice->params[0].send_b = 0; - voice->params[0].send_c = 0; - voice->params[0].send_d = 0; - - voice->params[0].send_routing = - 0xfff0 + card->mchannel_fx + voicenum; + // Multichannel pcm + voice->params[0].send_dcba=0xff; + voice->params[0].send_hgfe=0; + if (card->is_audigy) { + voice->params[0].send_routing = 0x3f3f3f00 + card->mchannel_fx + voicenum; + voice->params[0].send_routing2 = 0x3f3f3f3f; + } else { + voice->params[0].send_routing = 0xfff0 + card->mchannel_fx + voicenum; + } + } else { - voice->params[0].send_a = card->waveout.send_a[0]; - voice->params[0].send_b = card->waveout.send_b[0]; - voice->params[0].send_c = card->waveout.send_c[0]; - voice->params[0].send_d = card->waveout.send_d[0]; - - if (woinst->device) - voice->params[0].send_routing = 0x7654; - else - voice->params[0].send_routing = card->waveout.send_routing[0]; - } - - voice->params[0].volume_target = 0xffff; - voice->params[0].initial_fc = 0xff; - voice->params[0].initial_attn = 0x00; - voice->params[0].byampl_env_sustain = 0x7f; - voice->params[0].byampl_env_decay = 0x7f; + voice->params[0].send_dcba = card->waveout.send_dcba[SEND_MONO]; + voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_MONO]; + + if (woinst->device) { + voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM1]; + voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1]; + } else { + voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM]; + voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM]; + } + } } DPD(2, "voice: startloop=%#x, endloop=%#x\n", voice->startloop, voice->endloop); @@ -280,9 +293,16 @@ { struct emu10k1_card *card = wave_dev->card; struct woinst *woinst = wave_dev->woinst; + struct pt_data *pt = &card->pt; DPF(2, "emu10k1_waveout_start()\n"); + if (woinst->format.passthrough == 2) { + emu10k1_pt_setup(wave_dev); + sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 1); + pt->state = PT_STATE_PLAYING; + } + /* Actual start */ emu10k1_voices_start(woinst->voice, woinst->num_voices, woinst->total_played); diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/efxmgr.c linux-2.6.0-test1/sound/oss/emu10k1/efxmgr.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/efxmgr.c 2003-07-14 05:30:00.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/efxmgr.c 2003-07-15 03:11:58.000000000 +0200 @@ -80,15 +80,20 @@ if (addr < 0 || addr >= NUM_GPRS) return; - if (flag) - val += sblive_readptr(card, GPR_BASE + addr, 0); - - if (val > mgr->gpr[addr].max) - val = mgr->gpr[addr].max; - else if (val < mgr->gpr[addr].min) - val = mgr->gpr[addr].min; - - sblive_writeptr(card, GPR_BASE + addr, 0, val); + //fixme: once patch manager is up, remember to fix this for the audigy + if (card->is_audigy) { + sblive_writeptr(card, A_GPR_BASE + addr, 0, val); + } else { + if (flag) + val += sblive_readptr(card, GPR_BASE + addr, 0); + if (val > mgr->gpr[addr].max) + val = mgr->gpr[addr].max; + else if (val < mgr->gpr[addr].min) + val = mgr->gpr[addr].min; + sblive_writeptr(card, GPR_BASE + addr, 0, val); + } + + } //TODO: make this configurable: diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/efxmgr.h linux-2.6.0-test1/sound/oss/emu10k1/efxmgr.h --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/efxmgr.h 2003-07-14 05:38:49.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/efxmgr.h 2003-07-15 03:11:58.000000000 +0200 @@ -32,16 +32,30 @@ #ifndef _EFXMGR_H #define _EFXMGR_H -#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c)) +struct emu_efx_info_t{ + int opcode_shift; + int high_operand_shift; + int instruction_start; + int gpr_base; + int output_base; +}; + + +#define WRITE_EFX(a, b, c) sblive_writeptr((a), emu_efx_info[card->is_audigy].instruction_start + (b), 0, (c)) #define OP(op, z, w, x, y) \ - do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \ - WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \ + do { WRITE_EFX(card, (pc) * 2, ((x) << emu_efx_info[card->is_audigy].high_operand_shift) | (y)); \ + WRITE_EFX(card, (pc) * 2 + 1, ((op) << emu_efx_info[card->is_audigy].opcode_shift ) | ((z) << emu_efx_info[card->is_audigy].high_operand_shift) | (w)); \ ++pc; } while (0) #define NUM_INPUTS 0x20 #define NUM_OUTPUTS 0x20 #define NUM_GPRS 0x100 + +#define A_NUM_INPUTS 0x60 +#define A_NUM_OUTPUTS 0x60 //fixme: this may or may not be true +#define A_NUM_GPRS 0x200 + #define GPR_NAME_SIZE 32 #define PATCH_NAME_SIZE 32 @@ -98,6 +112,9 @@ #define GPR_BASE 0x100 #define OUTPUT_BASE 0x20 +#define A_GPR_BASE 0x400 +#define A_OUTPUT_BASE 0x60 + #define MAX_PATCHES_PAGES 32 struct patch_manager { diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/hwaccess.c linux-2.6.0-test1/sound/oss/emu10k1/hwaccess.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/hwaccess.c 2003-07-14 05:32:35.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/hwaccess.c 2003-07-15 03:11:58.000000000 +0200 @@ -160,6 +160,24 @@ return; } +void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + if (size == 32) + outl(data, card->iobase + (reg & 0x1F)); + else if (size == 16) + outw(data, card->iobase + (reg & 0x1F)); + else + outb(data, card->iobase + (reg & 0x1F)); + + spin_unlock_irqrestore(&card->lock, flags); + + return; +} + u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg) { u32 val; @@ -200,12 +218,13 @@ * write/read Emu10k1 pointer-offset register set, accessed through * * the PTR and DATA registers * *************************************************************************/ +#define A_PTR_ADDRESS_MASK 0x0fff0000 void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data) { u32 regptr; unsigned long flags; - regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); + regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); if (reg & 0xff000000) { u32 mask; @@ -242,7 +261,7 @@ spin_lock_irqsave(&card->lock, flags); while ((reg = va_arg(args, u32)) != TAGLIST_END) { u32 data = va_arg(args, u32); - u32 regptr = (((reg << 16) & PTR_ADDRESS_MASK) + u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK)); outl(regptr, card->iobase + PTR); if (reg & 0xff000000) { @@ -267,7 +286,7 @@ u32 regptr, val; unsigned long flags; - regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); + regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); if (reg & 0xff000000) { u32 mask; @@ -389,7 +408,7 @@ outb(reg, card->iobase + AC97ADDRESS); outw(value, card->iobase + AC97DATA); - + outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS); spin_unlock_irqrestore(&card->lock, flags); } @@ -402,15 +421,23 @@ unsigned long flags; int ret; - spin_lock_irqsave(&card->lock, flags); + if (card->is_audigy) { + if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) { + sblive_writeptr(card, A_MUDATA, 0, data); + ret = 0; + } else + ret = -1; + } else { + spin_lock_irqsave(&card->lock, flags); - if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { - outb(data, card->iobase + MUDATA); - ret = 0; - } else - ret = -1; + if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { + outb(data, card->iobase + MUDATA); + ret = 0; + } else + ret = -1; - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); + } return ret; } @@ -420,15 +447,23 @@ unsigned long flags; int ret; - spin_lock_irqsave(&card->lock, flags); + if (card->is_audigy) { + if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) { + *data = sblive_readptr(card, A_MUDATA,0); + ret = 0; + } else + ret = -1; + } else { + spin_lock_irqsave(&card->lock, flags); - if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) { - *data = inb(card->iobase + MUDATA); - ret = 0; - } else - ret = -1; + if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) { + *data = inb(card->iobase + MUDATA); + ret = 0; + } else + ret = -1; - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); + } return ret; } @@ -439,37 +474,54 @@ unsigned long flags; DPF(2, "emu10k1_mpu_reset()\n"); + if (card->is_audigy) { + if (card->mpuacqcount == 0) { + sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET); + sblive_wcwait(card, 8); + sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET); + sblive_wcwait(card, 8); + sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE); + sblive_wcwait(card, 8); + status = sblive_readptr(card, A_MUDATA, 0); + if (status == 0xfe) + return 0; + else + return -1; + } - if (card->mpuacqcount == 0) { - spin_lock_irqsave(&card->lock, flags); - outb(MUCMD_RESET, card->iobase + MUCMD); - spin_unlock_irqrestore(&card->lock, flags); + return 0; + } else { + if (card->mpuacqcount == 0) { + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_RESET, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); - sblive_wcwait(card, 8); + sblive_wcwait(card, 8); - spin_lock_irqsave(&card->lock, flags); - outb(MUCMD_RESET, card->iobase + MUCMD); - spin_unlock_irqrestore(&card->lock, flags); + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_RESET, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); - sblive_wcwait(card, 8); + sblive_wcwait(card, 8); - spin_lock_irqsave(&card->lock, flags); - outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD); - spin_unlock_irqrestore(&card->lock, flags); + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); - sblive_wcwait(card, 8); + sblive_wcwait(card, 8); - spin_lock_irqsave(&card->lock, flags); - status = inb(card->iobase + MUDATA); - spin_unlock_irqrestore(&card->lock, flags); + spin_lock_irqsave(&card->lock, flags); + status = inb(card->iobase + MUDATA); + spin_unlock_irqrestore(&card->lock, flags); - if (status == 0xfe) - return 0; - else - return -1; - } + if (status == 0xfe) + return 0; + else + return -1; + } - return 0; + return 0; + } } int emu10k1_mpu_acquire(struct emu10k1_card *card) diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/hwaccess.h linux-2.6.0-test1/sound/oss/emu10k1/hwaccess.h --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/hwaccess.h 2003-07-14 05:32:43.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/hwaccess.h 2003-07-15 03:11:58.000000000 +0200 @@ -79,13 +79,21 @@ struct emu10k1_waveout { - u16 send_routing[3]; - - u8 send_a[3]; - u8 send_b[3]; - u8 send_c[3]; - u8 send_d[3]; + u32 send_routing[3]; + // audigy only: + u32 send_routing2[3]; + + u32 send_dcba[3]; + // audigy only: + u32 send_hgfe[3]; }; +#define ROUTE_PCM 0 +#define ROUTE_PT 1 +#define ROUTE_PCM1 2 + +#define SEND_MONO 0 +#define SEND_LEFT 1 +#define SEND_RIGHT 2 struct emu10k1_wavein { @@ -129,7 +137,7 @@ #define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl) //up this number when breaking compatibility -#define PRIVATE3_VERSION 1 +#define PRIVATE3_VERSION 2 struct emu10k1_card { @@ -181,7 +189,7 @@ u32 has_toslink; // TOSLink detection u8 chiprev; /* Chip revision */ - + u8 is_audigy; u8 is_aps; struct patch_manager mgr; @@ -211,6 +219,7 @@ /* Hardware Abstraction Layer access functions */ void emu10k1_writefn0(struct emu10k1_card *, u32, u32); +void emu10k1_writefn0_2(struct emu10k1_card *, u32, u32, int); u32 emu10k1_readfn0(struct emu10k1_card *, u32); void emu10k1_timer_set(struct emu10k1_card *, u16); diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/irqmgr.h linux-2.6.0-test1/sound/oss/emu10k1/irqmgr.h --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/irqmgr.h 2003-07-14 05:31:57.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/irqmgr.h 2003-07-15 03:11:58.000000000 +0200 @@ -33,15 +33,15 @@ #define _IRQ_H /* EMU Irq Types */ -#define IRQTYPE_PCIBUSERROR IPR_PCIERROR -#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE) -#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK) -#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL) -#define IRQTYPE_MPUOUT IPR_MIDITRANSBUFEMPTY -#define IRQTYPE_MPUIN IPR_MIDIRECVBUFEMPTY -#define IRQTYPE_TIMER IPR_INTERVALTIMER -#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE) -#define IRQTYPE_DSP IPR_FXDSP +#define IRQTYPE_PCIBUSERROR IPR_PCIERROR +#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE) +#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK) +#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL) +#define IRQTYPE_MPUOUT (IPR_MIDITRANSBUFEMPTY | A_IPR_MIDITRANSBUFEMPTY2) +#define IRQTYPE_MPUIN (IPR_MIDIRECVBUFEMPTY | A_IPR_MIDIRECVBUFEMPTY2) +#define IRQTYPE_TIMER IPR_INTERVALTIMER +#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE) +#define IRQTYPE_DSP IPR_FXDSP void emu10k1_timer_irqhandler(struct emu10k1_card *); void emu10k1_dsp_irqhandler(struct emu10k1_card *); diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/main.c linux-2.6.0-test1/sound/oss/emu10k1/main.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/main.c 2003-07-14 05:38:46.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/main.c 2003-07-15 03:16:22.000000000 +0200 @@ -78,10 +78,11 @@ * Cleaned up poll() functions (audio and midi). Don't start input. * Restrict DMA pages used to 512Mib range. * New AC97_BOOST mixer ioctl. - * 0.19 Real fix for kernel with highmem support (cast dma_handle to u32). + * 0.19a Added Support for Audigy Cards + * Real fix for kernel with highmem support (cast dma_handle to u32). * Fix recording buffering parameters calculation. * Use unsigned long for variables in bit ops. - * 0.20 Fixed recording startup + * 0.20a Fixed recording startup * Fixed timer rate setting (it's a 16-bit register) *********************************************************************/ @@ -114,7 +115,6 @@ #define SNDCARD_EMU10K1 46 #endif -#define DRIVER_VERSION "0.20" /* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */ #define EMU10K1_DMA_MASK 0x1fffffff /* DMA buffer mask for pci_alloc_consist */ @@ -126,20 +126,27 @@ #ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1 #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 #endif +#ifndef PCI_DEVICE_ID_CREATIVE_AUDIGY +#define PCI_DEVICE_ID_CREATIVE_AUDIGY 0x0004 +#endif #define EMU_APS_SUBID 0x40011102 enum { EMU10K1 = 0, + AUDIGY, }; static char *card_names[] __devinitdata = { "EMU10K1", + "Audigy", }; static struct pci_device_id emu10k1_pci_tbl[] = { {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1}, + {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_AUDIGY, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, AUDIGY}, {0,} }; @@ -161,6 +168,67 @@ static int __devinit emu10k1_audio_init(struct emu10k1_card *card) { + /* Assign default playback voice parameters */ + if (card->is_audigy) + card->mchannel_fx = 0; + else + card->mchannel_fx = 8; + + + if (card->is_audigy) { + /* mono voice */ + card->waveout.send_dcba[SEND_MONO] = 0xffffffff; + card->waveout.send_hgfe[SEND_MONO] = 0x0000ffff; + + /* stereo voice */ + /* left */ + card->waveout.send_dcba[SEND_LEFT] = 0x00ff00ff; + card->waveout.send_hgfe[SEND_LEFT] = 0x00007f7f; + /* right */ + card->waveout.send_dcba[SEND_RIGHT] = 0xff00ff00; + card->waveout.send_hgfe[SEND_RIGHT] = 0x00007f7f; + + card->waveout.send_routing[ROUTE_PCM] = 0x03020100; // Regular pcm + card->waveout.send_routing2[ROUTE_PCM] = 0x07060504; + + card->waveout.send_routing[ROUTE_PT] = 0x3f3f3d3c; // Passthrough + card->waveout.send_routing2[ROUTE_PT] = 0x3f3f3f3f; + + card->waveout.send_routing[ROUTE_PCM1] = 0x03020100; // Spare + card->waveout.send_routing2[ROUTE_PCM1] = 0x07060404; + + } else { + /* mono voice */ + card->waveout.send_dcba[SEND_MONO] = 0x0000ffff; + + /* stereo voice */ + /* left */ + card->waveout.send_dcba[SEND_LEFT] = 0x000000ff; + /* right */ + card->waveout.send_dcba[SEND_RIGHT] = 0x0000ff00; + + card->waveout.send_routing[ROUTE_PCM] = 0x3210; // pcm + card->waveout.send_routing[ROUTE_PT] = 0x3210; // passthrough + card->waveout.send_routing[ROUTE_PCM1] = 0x7654; // /dev/dsp1 + } + + /* Assign default recording parameters */ + /* FIXME */ + if (card->is_aps) + card->wavein.recsrc = WAVERECORD_FX; + else + card->wavein.recsrc = WAVERECORD_AC97; + + card->wavein.fxwc = 0x0003; + return 0; +} + +static void emu10k1_audio_cleanup(struct emu10k1_card *card) +{ +} + +static int __devinit emu10k1_register_devices(struct emu10k1_card *card) +{ card->audio_dev = register_sound_dsp(&emu10k1_audio_fops, -1); if (card->audio_dev < 0) { printk(KERN_ERR "emu10k1: cannot register first audio device!\n"); @@ -173,56 +241,167 @@ goto err_dev1; } - /* Assign default playback voice parameters */ - card->mchannel_fx = 8; - /* mono voice */ - card->waveout.send_a[0] = 0xff; - card->waveout.send_b[0] = 0xff; - card->waveout.send_c[0] = 0x00; - card->waveout.send_d[0] = 0x00; - card->waveout.send_routing[0] = 0x3210; - - /* stereo voice */ - /* left */ - card->waveout.send_a[1] = 0xff; - card->waveout.send_b[1] = 0x00; - card->waveout.send_c[1] = 0x00; - card->waveout.send_d[1] = 0x00; - card->waveout.send_routing[1] = 0x3210; - - /* right */ - card->waveout.send_a[2] = 0x00; - card->waveout.send_b[2] = 0xff; - card->waveout.send_c[2] = 0x00; - card->waveout.send_d[2] = 0x00; - card->waveout.send_routing[2] = 0x3210; + card->ac97->dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1); + if (card->ac97->dev_mixer < 0) { + printk(KERN_ERR "emu10k1: cannot register mixer device\n"); + goto err_mixer; + } - /* Assign default recording parameters */ - /* FIXME */ - if (card->is_aps) - card->wavein.recsrc = WAVERECORD_FX; - else - card->wavein.recsrc = WAVERECORD_AC97; + card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1); + if (card->midi_dev < 0) { + printk(KERN_ERR "emu10k1: cannot register midi device!\n"); + goto err_midi; + } - card->wavein.fxwc = 0x0003; +#ifdef EMU10K1_SEQUENCER + card->seq_dev = sound_alloc_mididev(); + if (card->seq_dev == -1) + printk(KERN_WARNING "emu10k1: unable to register sequencer device!"); + else { + std_midi_synth.midi_dev = card->seq_dev; + midi_devs[card->seq_dev] = + (struct midi_operations *) + kmalloc(sizeof(struct midi_operations), GFP_KERNEL); + + if (midi_devs[card->seq_dev] == NULL) { + printk(KERN_ERR "emu10k1: unable to allocate memory!"); + sound_unload_mididev(card->seq_dev); + card->seq_dev = -1; + /* return without error */ + } else { + memcpy((char *)midi_devs[card->seq_dev], + (char *)&emu10k1_midi_operations, + sizeof(struct midi_operations)); + midi_devs[card->seq_dev]->devc = card; + sequencer_init(); + card->seq_mididev = NULL; + } + } +#endif return 0; +err_midi: + unregister_sound_mixer(card->ac97->dev_mixer); +err_mixer: + unregister_sound_dsp(card->audio_dev); err_dev1: unregister_sound_dsp(card->audio_dev); err_dev: return -ENODEV; } -static void __devinit emu10k1_audio_cleanup(struct emu10k1_card *card) +static void emu10k1_unregister_devices(struct emu10k1_card *card) { +#ifdef EMU10K1_SEQUENCER + if (card->seq_dev > -1) { + kfree(midi_devs[card->seq_dev]); + midi_devs[card->seq_dev] = NULL; + sound_unload_mididev(card->seq_dev); + card->seq_dev = -1; + } +#endif + + unregister_sound_midi(card->midi_dev); + unregister_sound_mixer(card->ac97->dev_mixer); unregister_sound_dsp(card->audio_dev1); unregister_sound_dsp(card->audio_dev); } -static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) +int emu10k1_info_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct emu10k1_card *card = data; + int len = 0; + + if (card == NULL) + return -ENODEV; + + len += sprintf (page + len, "Driver Version : %s\n", DRIVER_VERSION); + len += sprintf (page + len, "Card type : %s\n", card->is_aps ? "Aps" : (card->is_audigy ? "Audigy" : "Emu10k1")); + len += sprintf (page + len, "Revision : %d\n", card->chiprev); + len += sprintf (page + len, "Model : %#06x\n", card->model); + len += sprintf (page + len, "IO : %#06lx-%#06lx\n", card->iobase, card->iobase + card->length - 1); + len += sprintf (page + len, "IRQ : %d\n\n", card->irq); + + len += sprintf (page + len, "Registered /dev Entries:\n"); + len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev / 16); + len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev1 / 16); + len += sprintf (page + len, "/dev/mixer%d\n", card->ac97->dev_mixer / 16); + len += sprintf (page + len, "/dev/midi%d\n", card->midi_dev / 16); + +#ifdef EMU10K1_SEQUENCER + len += sprintf (page + len, "/dev/sequencer\n"); +#endif + + return len; +} + +static int __devinit emu10k1_proc_init(struct emu10k1_card *card) +{ + char s[48]; + + if (!proc_mkdir ("driver/emu10k1", 0)) { + printk(KERN_ERR "emu10k1: unable to create proc directory driver/emu10k1\n"); + goto err_out; + } + + sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); + if (!proc_mkdir (s, 0)) { + printk(KERN_ERR "emu10k1: unable to create proc directory %s\n", s); + goto err_emu10k1_proc; + } + + sprintf(s, "driver/emu10k1/%s/info", card->pci_dev->slot_name); + if (!create_proc_read_entry (s, 0, 0, emu10k1_info_proc, card)) { + printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s); + goto err_dev_proc; + } + + if (!card->is_aps) { + sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name); + if (!create_proc_read_entry (s, 0, 0, ac97_read_proc, card->ac97)) { + printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s); + goto err_proc_ac97; + } + } + + return 0; + +err_proc_ac97: + sprintf(s, "driver/emu10k1/%s/info", card->pci_dev->slot_name); + remove_proc_entry(s, NULL); + +err_dev_proc: + sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); + remove_proc_entry(s, NULL); + +err_emu10k1_proc: + remove_proc_entry("driver/emu10k1", NULL); + +err_out: + return -EIO; +} + +static void emu10k1_proc_cleanup(struct emu10k1_card *card) { - char s[32]; + char s[48]; + if (!card->is_aps) { + sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name); + remove_proc_entry(s, NULL); + } + + sprintf(s, "driver/emu10k1/%s/info", card->pci_dev->slot_name); + remove_proc_entry(s, NULL); + + sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); + remove_proc_entry(s, NULL); + + remove_proc_entry("driver/emu10k1", NULL); +} + +static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) +{ struct ac97_codec *codec = ac97_alloc_codec(); if(codec == NULL) @@ -231,15 +410,6 @@ return -EIO; } card->ac97 = codec; - -#warning "Initialisation order race. Must register after usable" - - card->ac97->dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1); - if (card->ac97->dev_mixer < 0) { - printk(KERN_ERR "emu10k1: cannot register mixer device\n"); - goto err_codec; - } - card->ac97->private_data = card; if (!card->is_aps) { @@ -261,23 +431,6 @@ // Force 5bit: //card->ac97->bit_resolution=5; - if (!proc_mkdir ("driver/emu10k1", 0)) { - printk(KERN_ERR "emu10k1: unable to create proc directory driver/emu10k1\n"); - goto err_out; - } - - sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); - if (!proc_mkdir (s, 0)) { - printk(KERN_ERR "emu10k1: unable to create proc directory %s\n", s); - goto err_emu10k1_proc; - } - - sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name); - if (!create_proc_read_entry (s, 0, 0, ac97_read_proc, card->ac97)) { - printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s); - goto err_ac97_proc; - } - /* these will store the original values and never be modified */ card->ac97_supported_mixers = card->ac97->supported_mixers; card->ac97_stereo_mixers = card->ac97->stereo_mixers; @@ -285,34 +438,13 @@ return 0; - err_ac97_proc: - sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); - remove_proc_entry(s, NULL); - - err_emu10k1_proc: - remove_proc_entry("driver/emu10k1", NULL); err_out: - unregister_sound_mixer (card->ac97->dev_mixer); - err_codec: ac97_release_codec(card->ac97); return -EIO; } -static void __devinit emu10k1_mixer_cleanup(struct emu10k1_card *card) +static void emu10k1_mixer_cleanup(struct emu10k1_card *card) { - char s[32]; - - if (!card->is_aps) { - sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name); - remove_proc_entry(s, NULL); - - sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); - remove_proc_entry(s, NULL); - - remove_proc_entry("driver/emu10k1", NULL); - } - - unregister_sound_mixer (card->ac97->dev_mixer); ac97_release_codec(card->ac97); } @@ -320,13 +452,6 @@ { int ret; - card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1); - if (card->midi_dev < 0) { - printk(KERN_ERR "emu10k1: cannot register midi device!\n"); - return -ENODEV; - } - - card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL); if (card->mpuout == NULL) { printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); @@ -366,31 +491,6 @@ goto err_out3; } -#ifdef EMU10K1_SEQUENCER - card->seq_dev = sound_alloc_mididev(); - if (card->seq_dev == -1) - printk(KERN_WARNING "emu10k1: unable to register sequencer device!"); - else { - std_midi_synth.midi_dev = card->seq_dev; - midi_devs[card->seq_dev] = - (struct midi_operations *) - kmalloc(sizeof(struct midi_operations), GFP_KERNEL); - - if (midi_devs[card->seq_dev] == NULL) { - printk(KERN_ERR "emu10k1: unable to allocate memory!"); - sound_unload_mididev(card->seq_dev); - card->seq_dev = -1; - return 0; - } else { - memcpy((char *)midi_devs[card->seq_dev], - (char *)&emu10k1_midi_operations, - sizeof(struct midi_operations)); - midi_devs[card->seq_dev]->devc = card; - sequencer_init(); - } - } - card->seq_mididev = 0; -#endif return 0; err_out3: @@ -398,28 +498,16 @@ err_out2: kfree(card->mpuout); err_out1: - unregister_sound_midi(card->midi_dev); return ret; } -static void __devinit emu10k1_midi_cleanup(struct emu10k1_card *card) +static void emu10k1_midi_cleanup(struct emu10k1_card *card) { tasklet_kill(&card->mpuout->tasklet); kfree(card->mpuout); tasklet_kill(&card->mpuin->tasklet); kfree(card->mpuin); - -#ifdef EMU10K1_SEQUENCER - if (card->seq_dev > -1) { - kfree(midi_devs[card->seq_dev]); - midi_devs[card->seq_dev] = NULL; - sound_unload_mididev(card->seq_dev); - card->seq_dev = -1; - } -#endif - - unregister_sound_midi(card->midi_dev); } static void __devinit voice_init(struct emu10k1_card *card) @@ -450,7 +538,7 @@ card->emupagetable[1] = MAXPAGES - 1; } -static void __devinit fx_cleanup(struct patch_manager *mgr) +static void fx_cleanup(struct patch_manager *mgr) { int i; for(i = 0; i < mgr->current_pages; i++) @@ -465,24 +553,25 @@ s32 left, right; int i; u32 pc = 0; - u32 patch_n; + u32 patch_n=0; + struct emu_efx_info_t emu_efx_info[2]= + {{ 20, 10, 0x400, 0x100, 0x20 }, + { 24, 12, 0x600, 0x400, 0x60 }, + }; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { mgr->ctrl_gpr[i][0] = -1; mgr->ctrl_gpr[i][1] = -1; } - for (i = 0; i < 512; i++) - OP(6, 0x40, 0x40, 0x40, 0x40); - - for (i = 0; i < 256; i++) - sblive_writeptr_tag(card, 0, - FXGPREGBASE + i, 0, - TANKMEMADDRREGBASE + i, 0, - TAGLIST_END); - /* !! The number bellow must equal the number of patches, currently 11 !! */ - mgr->current_pages = (11 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE; + if (card->is_audigy) + mgr->current_pages = (2 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE; + else + /* !! The number below must equal the number of patches, currently 11 !! */ + mgr->current_pages = (11 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE; + for (i = 0; i < mgr->current_pages; i++) { mgr->patch[i] = (void *)__get_free_page(GFP_KERNEL); if (mgr->patch[i] == NULL) { @@ -493,215 +582,298 @@ memset(mgr->patch[i], 0, PAGE_SIZE); } - pc = 0; - patch_n = 0; - //first free GPR = 0x11b - - /* FX volume correction and Volume control*/ - INPUT_PATCH_START(patch, "Pcm L vol", 0x0, 0); - GET_OUTPUT_GPR(patch, 0x100, 0x0); - GET_CONTROL_GPR(patch, 0x106, "Vol", 0, 0x7fffffff); - GET_DYNAMIC_GPR(patch, 0x112); - - OP(4, 0x112, 0x40, PCM_IN_L, 0x44); //*4 - OP(0, 0x100, 0x040, 0x112, 0x106); //*vol - INPUT_PATCH_END(patch); - - - INPUT_PATCH_START(patch, "Pcm R vol", 0x1, 0); - GET_OUTPUT_GPR(patch, 0x101, 0x1); - GET_CONTROL_GPR(patch, 0x107, "Vol", 0, 0x7fffffff); - GET_DYNAMIC_GPR(patch, 0x112); - - OP(4, 0x112, 0x40, PCM_IN_R, 0x44); - OP(0, 0x101, 0x040, 0x112, 0x107); - - INPUT_PATCH_END(patch); - - - // CD-Digital In Volume control - INPUT_PATCH_START(patch, "CD-Digital Vol L", 0x12, 0); - GET_OUTPUT_GPR(patch, 0x10c, 0x12); - GET_CONTROL_GPR(patch, 0x10d, "Vol", 0, 0x7fffffff); - - OP(0, 0x10c, 0x040, SPDIF_CD_L, 0x10d); - INPUT_PATCH_END(patch); - - INPUT_PATCH_START(patch, "CD-Digital Vol R", 0x13, 0); - GET_OUTPUT_GPR(patch, 0x10e, 0x13); - GET_CONTROL_GPR(patch, 0x10f, "Vol", 0, 0x7fffffff); - - OP(0, 0x10e, 0x040, SPDIF_CD_R, 0x10f); - INPUT_PATCH_END(patch); - - //Volume Correction for Multi-channel Inputs - INPUT_PATCH_START(patch, "Multi-Channel Gain", 0x08, 0); - patch->input=patch->output=0x3F00; - - GET_OUTPUT_GPR(patch, 0x113, MULTI_FRONT_L); - GET_OUTPUT_GPR(patch, 0x114, MULTI_FRONT_R); - GET_OUTPUT_GPR(patch, 0x115, MULTI_REAR_L); - GET_OUTPUT_GPR(patch, 0x116, MULTI_REAR_R); - GET_OUTPUT_GPR(patch, 0x117, MULTI_CENTER); - GET_OUTPUT_GPR(patch, 0x118, MULTI_LFE); - - OP(4, 0x113, 0x40, MULTI_FRONT_L, 0x44); - OP(4, 0x114, 0x40, MULTI_FRONT_R, 0x44); - OP(4, 0x115, 0x40, MULTI_REAR_L, 0x44); - OP(4, 0x116, 0x40, MULTI_REAR_R, 0x44); - OP(4, 0x117, 0x40, MULTI_CENTER, 0x44); - OP(4, 0x118, 0x40, MULTI_LFE, 0x44); - - INPUT_PATCH_END(patch); - - - //Routing patch start - ROUTING_PATCH_START(rpatch, "Routing"); - GET_INPUT_GPR(rpatch, 0x100, 0x0); - GET_INPUT_GPR(rpatch, 0x101, 0x1); - GET_INPUT_GPR(rpatch, 0x10c, 0x12); - GET_INPUT_GPR(rpatch, 0x10e, 0x13); - GET_INPUT_GPR(rpatch, 0x113, MULTI_FRONT_L); - GET_INPUT_GPR(rpatch, 0x114, MULTI_FRONT_R); - GET_INPUT_GPR(rpatch, 0x115, MULTI_REAR_L); - GET_INPUT_GPR(rpatch, 0x116, MULTI_REAR_R); - GET_INPUT_GPR(rpatch, 0x117, MULTI_CENTER); - GET_INPUT_GPR(rpatch, 0x118, MULTI_LFE); - - GET_DYNAMIC_GPR(rpatch, 0x102); - GET_DYNAMIC_GPR(rpatch, 0x103); - - GET_OUTPUT_GPR(rpatch, 0x104, 0x8); - GET_OUTPUT_GPR(rpatch, 0x105, 0x9); - GET_OUTPUT_GPR(rpatch, 0x10a, 0x2); - GET_OUTPUT_GPR(rpatch, 0x10b, 0x3); - - - /* input buffer */ - OP(6, 0x102, AC97_IN_L, 0x40, 0x40); - OP(6, 0x103, AC97_IN_R, 0x40, 0x40); - - - /* Digital In + PCM + MULTI_FRONT-> AC97 out (front speakers)*/ - OP(6, AC97_FRONT_L, 0x100, 0x10c, 0x113); - - CONNECT(MULTI_FRONT_L, AC97_FRONT_L); - CONNECT(PCM_IN_L, AC97_FRONT_L); - CONNECT(SPDIF_CD_L, AC97_FRONT_L); - - OP(6, AC97_FRONT_R, 0x101, 0x10e, 0x114); - - CONNECT(MULTI_FRONT_R, AC97_FRONT_R); - CONNECT(PCM_IN_R, AC97_FRONT_R); - CONNECT(SPDIF_CD_R, AC97_FRONT_R); - - /* Digital In + PCM + AC97 In + PCM1 + MULTI_REAR --> Rear Channel */ - OP(6, 0x104, PCM1_IN_L, 0x100, 0x115); - OP(6, 0x104, 0x104, 0x10c, 0x102); - - CONNECT(MULTI_REAR_L, ANALOG_REAR_L); - CONNECT(AC97_IN_L, ANALOG_REAR_L); - CONNECT(PCM_IN_L, ANALOG_REAR_L); - CONNECT(SPDIF_CD_L, ANALOG_REAR_L); - CONNECT(PCM1_IN_L, ANALOG_REAR_L); - - OP(6, 0x105, PCM1_IN_R, 0x101, 0x116); - OP(6, 0x105, 0x105, 0x10e, 0x103); - - CONNECT(MULTI_REAR_R, ANALOG_REAR_R); - CONNECT(AC97_IN_R, ANALOG_REAR_R); - CONNECT(PCM_IN_R, ANALOG_REAR_R); - CONNECT(SPDIF_CD_R, ANALOG_REAR_R); - CONNECT(PCM1_IN_R, ANALOG_REAR_R); - - /* Digital In + PCM + AC97 In + MULTI_FRONT --> Digital out */ - OP(6, 0x10a, 0x100, 0x102, 0x10c); - OP(6, 0x10a, 0x10a, 0x113, 0x40); - - CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L); - CONNECT(PCM_IN_L, DIGITAL_OUT_L); - CONNECT(AC97_IN_L, DIGITAL_OUT_L); - CONNECT(SPDIF_CD_L, DIGITAL_OUT_L); - - OP(6, 0x10b, 0x101, 0x103, 0x10e); - OP(6, 0x10b, 0x10b, 0x114, 0x40); - - CONNECT(MULTI_FRONT_R, DIGITAL_OUT_R); - CONNECT(PCM_IN_R, DIGITAL_OUT_R); - CONNECT(AC97_IN_R, DIGITAL_OUT_R); - CONNECT(SPDIF_CD_R, DIGITAL_OUT_R); - - /* AC97 In --> ADC Recording Buffer */ - OP(6, ADC_REC_L, 0x102, 0x40, 0x40); - - CONNECT(AC97_IN_L, ADC_REC_L); - - OP(6, ADC_REC_R, 0x103, 0x40, 0x40); - - CONNECT(AC97_IN_R, ADC_REC_R); + if (card->is_audigy) { + for (i = 0; i < 1024; i++) + OP(0xf, 0x0c0, 0x0c0, 0x0cf, 0x0c0); + + for (i = 0; i < 512 ; i++) + sblive_writeptr(card, A_GPR_BASE+i,0,0); + + pc=0; + + //Pcm input volume + OP(0, 0x402, 0x0c0, 0x406, 0x000); + OP(0, 0x403, 0x0c0, 0x407, 0x001); + + //CD-Digital input Volume + OP(0, 0x404, 0x0c0, 0x40d, 0x42); + OP(0, 0x405, 0x0c0, 0x40f, 0x43); + + // CD + PCM + OP(6, 0x400, 0x0c0, 0x402, 0x404); + OP(6, 0x401, 0x0c0, 0x403, 0x405); + + // Front Output + Master Volume + OP(0, 0x68, 0x0c0, 0x408, 0x400); + OP(0, 0x69, 0x0c0, 0x409, 0x401); + + // Add-in analog inputs for other speakers + OP(6, 0x400, 0x40, 0x400, 0xc0); + OP(6, 0x401, 0x41, 0x401, 0xc0); + + // Digital Front + Master Volume + OP(0, 0x60, 0x0c0, 0x408, 0x400); + OP(0, 0x61, 0x0c0, 0x409, 0x401); + + // Rear Output + Rear Volume + OP(0, 0x06e, 0x0c0, 0x419, 0x400); + OP(0, 0x06f, 0x0c0, 0x41a, 0x401); + + // Digital Rear Output + Rear Volume + OP(0, 0x066, 0x0c0, 0x419, 0x400); + OP(0, 0x067, 0x0c0, 0x41a, 0x401); + + // Audigy Drive, Headphone out + OP(6, 0x64, 0x0c0, 0x0c0, 0x400); + OP(6, 0x65, 0x0c0, 0x0c0, 0x401); + + // ac97 Recording + OP(6, 0x76, 0x0c0, 0x0c0, 0x40); + OP(6, 0x77, 0x0c0, 0x0c0, 0x41); + + // Center = sub = Left/2 + Right/2 + OP(0xe, 0x400, 0x401, 0xcd, 0x400); + + // center/sub Volume (master) + OP(0, 0x06a, 0x0c0, 0x408, 0x400); + OP(0, 0x06b, 0x0c0, 0x409, 0x400); + + // Digital center/sub Volume (master) + OP(0, 0x062, 0x0c0, 0x408, 0x400); + OP(0, 0x063, 0x0c0, 0x409, 0x400); + + ROUTING_PATCH_START(rpatch, "Routing"); + ROUTING_PATCH_END(rpatch); + + /* delimiter patch */ + patch = PATCH(mgr, patch_n); + patch->code_size = 0; + + sblive_writeptr(card, 0x53, 0, 0); + } else { + for (i = 0; i < 512 ; i++) + OP(6, 0x40, 0x40, 0x40, 0x40); + + for (i = 0; i < 256; i++) + sblive_writeptr_tag(card, 0, + FXGPREGBASE + i, 0, + TANKMEMADDRREGBASE + i, 0, + TAGLIST_END); - /* fx12:Analog-Center */ - OP(6, ANALOG_CENTER, 0x117, 0x40, 0x40); - CONNECT(MULTI_CENTER, ANALOG_CENTER); + + pc = 0; - /* fx11:Analog-LFE */ - OP(6, ANALOG_LFE, 0x118, 0x40, 0x40); - CONNECT(MULTI_LFE, ANALOG_LFE); + //first free GPR = 0x11b + + + /* FX volume correction and Volume control*/ + INPUT_PATCH_START(patch, "Pcm L vol", 0x0, 0); + GET_OUTPUT_GPR(patch, 0x100, 0x0); + GET_CONTROL_GPR(patch, 0x106, "Vol", 0, 0x7fffffff); + GET_DYNAMIC_GPR(patch, 0x112); + + OP(4, 0x112, 0x40, PCM_IN_L, 0x44); //*4 + OP(0, 0x100, 0x040, 0x112, 0x106); //*vol + INPUT_PATCH_END(patch); + + + INPUT_PATCH_START(patch, "Pcm R vol", 0x1, 0); + GET_OUTPUT_GPR(patch, 0x101, 0x1); + GET_CONTROL_GPR(patch, 0x107, "Vol", 0, 0x7fffffff); + GET_DYNAMIC_GPR(patch, 0x112); + + OP(4, 0x112, 0x40, PCM_IN_R, 0x44); + OP(0, 0x101, 0x040, 0x112, 0x107); + + INPUT_PATCH_END(patch); + + + // CD-Digital In Volume control + INPUT_PATCH_START(patch, "CD-Digital Vol L", 0x12, 0); + GET_OUTPUT_GPR(patch, 0x10c, 0x12); + GET_CONTROL_GPR(patch, 0x10d, "Vol", 0, 0x7fffffff); + + OP(0, 0x10c, 0x040, SPDIF_CD_L, 0x10d); + INPUT_PATCH_END(patch); + + INPUT_PATCH_START(patch, "CD-Digital Vol R", 0x13, 0); + GET_OUTPUT_GPR(patch, 0x10e, 0x13); + GET_CONTROL_GPR(patch, 0x10f, "Vol", 0, 0x7fffffff); + + OP(0, 0x10e, 0x040, SPDIF_CD_R, 0x10f); + INPUT_PATCH_END(patch); + + //Volume Correction for Multi-channel Inputs + INPUT_PATCH_START(patch, "Multi-Channel Gain", 0x08, 0); + patch->input=patch->output=0x3F00; + + GET_OUTPUT_GPR(patch, 0x113, MULTI_FRONT_L); + GET_OUTPUT_GPR(patch, 0x114, MULTI_FRONT_R); + GET_OUTPUT_GPR(patch, 0x115, MULTI_REAR_L); + GET_OUTPUT_GPR(patch, 0x116, MULTI_REAR_R); + GET_OUTPUT_GPR(patch, 0x117, MULTI_CENTER); + GET_OUTPUT_GPR(patch, 0x118, MULTI_LFE); + + OP(4, 0x113, 0x40, MULTI_FRONT_L, 0x44); + OP(4, 0x114, 0x40, MULTI_FRONT_R, 0x44); + OP(4, 0x115, 0x40, MULTI_REAR_L, 0x44); + OP(4, 0x116, 0x40, MULTI_REAR_R, 0x44); + OP(4, 0x117, 0x40, MULTI_CENTER, 0x44); + OP(4, 0x118, 0x40, MULTI_LFE, 0x44); + + INPUT_PATCH_END(patch); - /* fx12:Digital-Center */ - OP(6, DIGITAL_CENTER, 0x117, 0x40, 0x40); - CONNECT(MULTI_CENTER, DIGITAL_CENTER); - /* fx11:Analog-LFE */ - OP(6, DIGITAL_LFE, 0x118, 0x40, 0x40); - CONNECT(MULTI_LFE, DIGITAL_LFE); + //Routing patch start + ROUTING_PATCH_START(rpatch, "Routing"); + GET_INPUT_GPR(rpatch, 0x100, 0x0); + GET_INPUT_GPR(rpatch, 0x101, 0x1); + GET_INPUT_GPR(rpatch, 0x10c, 0x12); + GET_INPUT_GPR(rpatch, 0x10e, 0x13); + GET_INPUT_GPR(rpatch, 0x113, MULTI_FRONT_L); + GET_INPUT_GPR(rpatch, 0x114, MULTI_FRONT_R); + GET_INPUT_GPR(rpatch, 0x115, MULTI_REAR_L); + GET_INPUT_GPR(rpatch, 0x116, MULTI_REAR_R); + GET_INPUT_GPR(rpatch, 0x117, MULTI_CENTER); + GET_INPUT_GPR(rpatch, 0x118, MULTI_LFE); + + GET_DYNAMIC_GPR(rpatch, 0x102); + GET_DYNAMIC_GPR(rpatch, 0x103); + + GET_OUTPUT_GPR(rpatch, 0x104, 0x8); + GET_OUTPUT_GPR(rpatch, 0x105, 0x9); + GET_OUTPUT_GPR(rpatch, 0x10a, 0x2); + GET_OUTPUT_GPR(rpatch, 0x10b, 0x3); + + + /* input buffer */ + OP(6, 0x102, AC97_IN_L, 0x40, 0x40); + OP(6, 0x103, AC97_IN_R, 0x40, 0x40); + + + /* Digital In + PCM + MULTI_FRONT-> AC97 out (front speakers)*/ + OP(6, AC97_FRONT_L, 0x100, 0x10c, 0x113); + + CONNECT(MULTI_FRONT_L, AC97_FRONT_L); + CONNECT(PCM_IN_L, AC97_FRONT_L); + CONNECT(SPDIF_CD_L, AC97_FRONT_L); + + OP(6, AC97_FRONT_R, 0x101, 0x10e, 0x114); + + CONNECT(MULTI_FRONT_R, AC97_FRONT_R); + CONNECT(PCM_IN_R, AC97_FRONT_R); + CONNECT(SPDIF_CD_R, AC97_FRONT_R); + + /* Digital In + PCM + AC97 In + PCM1 + MULTI_REAR --> Rear Channel */ + OP(6, 0x104, PCM1_IN_L, 0x100, 0x115); + OP(6, 0x104, 0x104, 0x10c, 0x102); + + CONNECT(MULTI_REAR_L, ANALOG_REAR_L); + CONNECT(AC97_IN_L, ANALOG_REAR_L); + CONNECT(PCM_IN_L, ANALOG_REAR_L); + CONNECT(SPDIF_CD_L, ANALOG_REAR_L); + CONNECT(PCM1_IN_L, ANALOG_REAR_L); + + OP(6, 0x105, PCM1_IN_R, 0x101, 0x116); + OP(6, 0x105, 0x105, 0x10e, 0x103); + + CONNECT(MULTI_REAR_R, ANALOG_REAR_R); + CONNECT(AC97_IN_R, ANALOG_REAR_R); + CONNECT(PCM_IN_R, ANALOG_REAR_R); + CONNECT(SPDIF_CD_R, ANALOG_REAR_R); + CONNECT(PCM1_IN_R, ANALOG_REAR_R); + + /* Digital In + PCM + AC97 In + MULTI_FRONT --> Digital out */ + OP(6, 0x10b, 0x100, 0x102, 0x10c); + OP(6, 0x10b, 0x10b, 0x113, 0x40); + + CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L); + CONNECT(PCM_IN_L, DIGITAL_OUT_L); + CONNECT(AC97_IN_L, DIGITAL_OUT_L); + CONNECT(SPDIF_CD_L, DIGITAL_OUT_L); + + OP(6, 0x10a, 0x101, 0x103, 0x10e); + OP(6, 0x10b, 0x10b, 0x114, 0x40); + + CONNECT(MULTI_FRONT_R, DIGITAL_OUT_R); + CONNECT(PCM_IN_R, DIGITAL_OUT_R); + CONNECT(AC97_IN_R, DIGITAL_OUT_R); + CONNECT(SPDIF_CD_R, DIGITAL_OUT_R); + + /* AC97 In --> ADC Recording Buffer */ + OP(6, ADC_REC_L, 0x102, 0x40, 0x40); + + CONNECT(AC97_IN_L, ADC_REC_L); + + OP(6, ADC_REC_R, 0x103, 0x40, 0x40); + + CONNECT(AC97_IN_R, ADC_REC_R); + + + /* fx12:Analog-Center */ + OP(6, ANALOG_CENTER, 0x117, 0x40, 0x40); + CONNECT(MULTI_CENTER, ANALOG_CENTER); + + /* fx11:Analog-LFE */ + OP(6, ANALOG_LFE, 0x118, 0x40, 0x40); + CONNECT(MULTI_LFE, ANALOG_LFE); + + /* fx12:Digital-Center */ + OP(6, DIGITAL_CENTER, 0x117, 0x40, 0x40); + CONNECT(MULTI_CENTER, DIGITAL_CENTER); + + /* fx11:Analog-LFE */ + OP(6, DIGITAL_LFE, 0x118, 0x40, 0x40); + CONNECT(MULTI_LFE, DIGITAL_LFE); - ROUTING_PATCH_END(rpatch); + ROUTING_PATCH_END(rpatch); - // Rear volume control - OUTPUT_PATCH_START(patch, "Vol Rear L", 0x8, 0); - GET_INPUT_GPR(patch, 0x104, 0x8); - GET_CONTROL_GPR(patch, 0x119, "Vol", 0, 0x7fffffff); + // Rear volume control + OUTPUT_PATCH_START(patch, "Vol Rear L", 0x8, 0); + GET_INPUT_GPR(patch, 0x104, 0x8); + GET_CONTROL_GPR(patch, 0x119, "Vol", 0, 0x7fffffff); - OP(0, ANALOG_REAR_L, 0x040, 0x104, 0x119); - OUTPUT_PATCH_END(patch); + OP(0, ANALOG_REAR_L, 0x040, 0x104, 0x119); + OUTPUT_PATCH_END(patch); + OUTPUT_PATCH_START(patch, "Vol Rear R", 0x9, 0); + GET_INPUT_GPR(patch, 0x105, 0x9); + GET_CONTROL_GPR(patch, 0x11a, "Vol", 0, 0x7fffffff); - OUTPUT_PATCH_START(patch, "Vol Rear R", 0x9, 0); - GET_INPUT_GPR(patch, 0x105, 0x9); - GET_CONTROL_GPR(patch, 0x11a, "Vol", 0, 0x7fffffff); + OP(0, ANALOG_REAR_R, 0x040, 0x105, 0x11a); + OUTPUT_PATCH_END(patch); - OP(0, ANALOG_REAR_R, 0x040, 0x105, 0x11a); - OUTPUT_PATCH_END(patch); + //Master volume control on front-digital + OUTPUT_PATCH_START(patch, "Vol Master L", 0x2, 1); + GET_INPUT_GPR(patch, 0x10a, 0x2); + GET_CONTROL_GPR(patch, 0x108, "Vol", 0, 0x7fffffff); - //Master volume control on front-digital - OUTPUT_PATCH_START(patch, "Vol Master L", 0x2, 1); - GET_INPUT_GPR(patch, 0x10a, 0x2); - GET_CONTROL_GPR(patch, 0x108, "Vol", 0, 0x7fffffff); + OP(0, DIGITAL_OUT_L, 0x040, 0x10a, 0x108); + OUTPUT_PATCH_END(patch); - OP(0, DIGITAL_OUT_L, 0x040, 0x10a, 0x108); - OUTPUT_PATCH_END(patch); + OUTPUT_PATCH_START(patch, "Vol Master R", 0x3, 1); + GET_INPUT_GPR(patch, 0x10b, 0x3); + GET_CONTROL_GPR(patch, 0x109, "Vol", 0, 0x7fffffff); - OUTPUT_PATCH_START(patch, "Vol Master R", 0x3, 1); - GET_INPUT_GPR(patch, 0x10b, 0x3); - GET_CONTROL_GPR(patch, 0x109, "Vol", 0, 0x7fffffff); + OP(0, DIGITAL_OUT_R, 0x040, 0x10b, 0x109); + OUTPUT_PATCH_END(patch); - OP(0, DIGITAL_OUT_R, 0x040, 0x10b, 0x109); - OUTPUT_PATCH_END(patch); + /* delimiter patch */ + patch = PATCH(mgr, patch_n); + patch->code_size = 0; - /* delimiter patch */ - patch = PATCH(mgr, patch_n); - patch->code_size = 0; - - sblive_writeptr(card, DBG, 0, 0); + + sblive_writeptr(card, DBG, 0, 0); + } mgr->lock = SPIN_LOCK_UNLOCKED; + // Set up Volume controls, try to keep this the same for both Audigy and Live //Master volume mgr->ctrl_gpr[SOUND_MIXER_VOLUME][0] = 8; @@ -749,8 +921,16 @@ emu10k1_set_volume_gpr(card, 0xd, left, VOL_5BIT); emu10k1_set_volume_gpr(card, 0xf, right, VOL_5BIT); - //hard wire the ac97's pcm, we'll do that in dsp code instead. - emu10k1_ac97_write(card->ac97, 0x18, 0x0); + + //hard wire the ac97's pcm, pcm volume is done above using dsp code. + if (card->is_audigy) + //for Audigy, we mute it and use the philips 6 channel DAC instead + emu10k1_ac97_write(card->ac97, 0x18, 0x8000); + else + //For the Live we hardwire it to full volume + emu10k1_ac97_write(card->ac97, 0x18, 0x0); + + //remove it from the ac97_codec's control card->ac97_supported_mixers &= ~SOUND_MASK_PCM; card->ac97_stereo_mixers &= ~SOUND_MASK_PCM; @@ -789,6 +969,13 @@ SOLEH, 0, TAGLIST_END); + if (card->is_audigy) { + sblive_writeptr_tag(card,0, + 0x5e,0xf00, + 0x5f,0x3, + TAGLIST_END); + } + /* Init envelope engine */ for (nCh = 0; nCh < NUM_G; nCh++) { sblive_writeptr_tag(card, nCh, @@ -824,6 +1011,21 @@ ENVVAL, 0, TAGLIST_END); sblive_writeptr(card, CPF, nCh, 0); + /* + Audigy FXRT initialization + reversed eng'd, may not be accurate. + */ + if (card->is_audigy) { + sblive_writeptr_tag(card,nCh, + 0x4c,0x0, + 0x4d,0x0, + 0x4e,0x0, + 0x4f,0x0, + A_FXRT1, 0x3f3f3f3f, + A_FXRT2, 0x3f3f3f3f, + A_SENDAMOUNTS, 0, + TAGLIST_END); + } } @@ -858,6 +1060,25 @@ TAGLIST_END); + if (card->is_audigy && (card->chiprev == 4)) { + /* Hacks for Alice3 to work independent of haP16V driver */ + u32 tmp; + + //Setup SRCMulti_I2S SamplingRate + tmp = sblive_readptr(card, A_SPDIF_SAMPLERATE, 0); + tmp &= 0xfffff1ff; + tmp |= (0x2<<9); + sblive_writeptr(card, A_SPDIF_SAMPLERATE, 0, tmp); + + /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ + emu10k1_writefn0(card, 0x20, 0x600000); + emu10k1_writefn0(card, 0x24, 0x14); + + /* Setup SRCMulti Input Audio Enable */ + emu10k1_writefn0(card, 0x20, 0x6E0000); + emu10k1_writefn0(card, 0x24, 0xFF00FF00); + } + ret = fx_init(card); /* initialize effects engine */ if (ret < 0) return ret; @@ -905,16 +1126,30 @@ /* Lock Tank Memory = 1 */ /* Lock Sound Memory = 0 */ /* Auto Mute = 1 */ - - if (card->model == 0x20 || card->model == 0xc400 || - (card->model == 0x21 && card->chiprev < 6)) - emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE); - else - emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE); - + if (card->is_audigy) { + if (card->chiprev == 4) + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | HCFG_AC3ENABLE_GPSPDIF | HCFG_AUTOMUTE | HCFG_JOYENABLE); + else + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AUTOMUTE | HCFG_JOYENABLE); + } else { + if (card->model == 0x20 || card->model == 0xc400 || + (card->model == 0x21 && card->chiprev < 6)) + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE); + else + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE); + } /* Enable Vol_Ctrl irqs */ emu10k1_irq_enable(card, INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_FXDSPENABLE); + if (card->is_audigy && (card->chiprev == 4)) { + /* Unmute Analog now. Set GPO6 to 1 for Apollo. + * This has to be done after init ALice3 I2SOut beyond 48KHz. + * So, sequence is important. */ + u32 tmp = emu10k1_readfn0(card, A_IOCFG); + tmp |= 0x0040; + emu10k1_writefn0(card, A_IOCFG, tmp); + } + /* FIXME: TOSLink detection */ card->has_toslink = 0; @@ -967,7 +1202,7 @@ return 0; } -static void __devinit emu10k1_cleanup(struct emu10k1_card *card) +static void emu10k1_cleanup(struct emu10k1_card *card) { int ch; @@ -1012,6 +1247,8 @@ SOLEH, 0, TAGLIST_END); + if (card->is_audigy) + sblive_writeptr(card, 0, A_DBG, A_DBG_SINGLE_STEP); pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle); pci_free_consistent(card->pci_dev, card->silentpage.size, card->silentpage.addr, card->silentpage.dma_handle); @@ -1074,6 +1311,9 @@ card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase, card->iobase + card->length - 1, card->irq); + if (pci_id->device == PCI_DEVICE_ID_CREATIVE_AUDIGY) + card->is_audigy = 1; + pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid); card->is_aps = (subsysvid == EMU_APS_SUBID); @@ -1083,13 +1323,13 @@ init_waitqueue_head(&card->open_wait); ret = emu10k1_audio_init(card); - if(ret < 0) { + if (ret < 0) { printk(KERN_ERR "emu10k1: cannot initialize audio devices\n"); goto err_audio; } ret = emu10k1_mixer_init(card); - if(ret < 0) { + if (ret < 0) { printk(KERN_ERR "emu10k1: cannot initialize AC97 codec\n"); goto err_mixer; } @@ -1109,10 +1349,28 @@ if (card->is_aps) emu10k1_ecard_init(card); + ret = emu10k1_register_devices(card); + if (ret < 0) + goto err_register; + + /* proc entries must be created after registering devices, as + * emu10k1_info_proc prints card->audio_dev &co. */ + ret = emu10k1_proc_init(card); + if (ret < 0) { + printk(KERN_ERR "emu10k1: cannot initialize proc directory\n"); + goto err_proc; + } + list_add(&card->list, &emu10k1_devs); return 0; +err_proc: + emu10k1_unregister_devices(card); + +err_register: + emu10k1_cleanup(card); + err_emu10k1_init: emu10k1_midi_cleanup(card); @@ -1141,9 +1399,11 @@ list_del(&card->list); + emu10k1_unregister_devices(card); emu10k1_cleanup(card); emu10k1_midi_cleanup(card); emu10k1_mixer_cleanup(card); + emu10k1_proc_cleanup(card); emu10k1_audio_cleanup(card); free_irq(card->irq, card); release_region(card->iobase, card->length); diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/midi.h linux-2.6.0-test1/sound/oss/emu10k1/midi.h --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/midi.h 2003-07-14 05:31:50.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/midi.h 2003-07-15 03:11:58.000000000 +0200 @@ -52,4 +52,27 @@ struct list_head mid_hdrs; }; +/* uncomment next line to use midi port on Audigy drive */ +//#define USE_AUDIGY_DRIVE_MIDI + +#ifdef USE_AUDIGY_DRIVE_MIDI +#define A_MUDATA A_MUDATA2 +#define A_MUCMD A_MUCMD2 +#define A_MUSTAT A_MUCMD2 +#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY2 +#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY2 +#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE2 +#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE2 +#else +#define A_MUDATA A_MUDATA1 +#define A_MUCMD A_MUCMD1 +#define A_MUSTAT A_MUCMD1 +#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY1 +#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY1 +#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE1 +#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE1 +#endif + + #endif /* _MIDI_H */ + diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/mixer.c linux-2.6.0-test1/sound/oss/emu10k1/mixer.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/mixer.c 2003-07-14 05:36:33.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/mixer.c 2003-07-15 03:11:58.000000000 +0200 @@ -136,7 +136,7 @@ r = (r * 40 + 50) / 100; for (i = 0; i < 5; i++) - sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]); + sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]); } static void set_treble(struct emu10k1_card *card, int l, int r) @@ -147,7 +147,7 @@ r = (r * 40 + 50) / 100; for (i = 0; i < 5; i++) - sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]); + sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]); } const char volume_params[SOUND_MIXER_NRDEVICES]= { @@ -206,22 +206,25 @@ switch (ctl->cmd) { #ifdef DBGEMU case CMD_WRITEFN0: - emu10k1_writefn0(card, ctl->val[0], ctl->val[1]); + emu10k1_writefn0_2(card, ctl->val[0], ctl->val[1], ctl->val[2]); break; - +#endif case CMD_WRITEPTR: - if (ctl->val[1] >= 0x40 || ctl->val[0] > 0xff) { +#ifdef DBGEMU + if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000) { +#else + if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000 || ((ctl->val[0] < 0x100 ) && + //Any register allowed raw access goes here: + (ctl->val[0] != A_SPDIF_SAMPLERATE) && (ctl->val[0] != A_DBG) + ) + ) { +#endif ret = -EINVAL; break; } - - if ((ctl->val[0] & 0x7ff) > 0x3f) - ctl->val[1] = 0x00; - sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]); - break; -#endif + case CMD_READFN0: ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]); @@ -286,16 +289,13 @@ case CMD_GETVOICEPARAM: ctl->val[0] = card->waveout.send_routing[0]; - ctl->val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 | - card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24; + ctl->val[1] = card->waveout.send_dcba[0]; ctl->val[2] = card->waveout.send_routing[1]; - ctl->val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 | - card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24; + ctl->val[3] = card->waveout.send_dcba[1]; ctl->val[4] = card->waveout.send_routing[2]; - ctl->val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 | - card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24; + ctl->val[5] = card->waveout.send_dcba[2]; if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl))) ret = -EFAULT; @@ -303,23 +303,14 @@ break; case CMD_SETVOICEPARAM: - card->waveout.send_routing[0] = ctl->val[0] & 0xffff; - card->waveout.send_a[0] = ctl->val[1] & 0xff; - card->waveout.send_b[0] = (ctl->val[1] >> 8) & 0xff; - card->waveout.send_c[0] = (ctl->val[1] >> 16) & 0xff; - card->waveout.send_d[0] = (ctl->val[1] >> 24) & 0xff; - - card->waveout.send_routing[1] = ctl->val[2] & 0xffff; - card->waveout.send_a[1] = ctl->val[3] & 0xff; - card->waveout.send_b[1] = (ctl->val[3] >> 8) & 0xff; - card->waveout.send_c[1] = (ctl->val[3] >> 16) & 0xff; - card->waveout.send_d[1] = (ctl->val[3] >> 24) & 0xff; - - card->waveout.send_routing[2] = ctl->val[4] & 0xffff; - card->waveout.send_a[2] = ctl->val[5] & 0xff; - card->waveout.send_b[2] = (ctl->val[5] >> 8) & 0xff; - card->waveout.send_c[2] = (ctl->val[5] >> 16) & 0xff; - card->waveout.send_d[2] = (ctl->val[5] >> 24) & 0xff; + card->waveout.send_routing[0] = ctl->val[0]; + card->waveout.send_dcba[0] = ctl->val[1]; + + card->waveout.send_routing[1] = ctl->val[2]; + card->waveout.send_dcba[1] = ctl->val[3]; + + card->waveout.send_routing[2] = ctl->val[4]; + card->waveout.send_dcba[2] = ctl->val[5]; break; @@ -416,12 +407,16 @@ break; case CMD_SETGPOUT: - if (ctl->val[0] > 2 || ctl->val[1] > 1) { + if ( ((ctl->val[0] > 2) && (!card->is_audigy)) + || (ctl->val[0] > 15) || ctl->val[1] > 1) { ret= -EINVAL; break; } - emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]); + if (card->is_audigy) + emu10k1_writefn0(card, (1 << 24) | ((ctl->val[0]) << 16) | A_IOCFG, ctl->val[1]); + else + emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]); break; case CMD_GETGPR2OSS: @@ -493,13 +488,20 @@ break; case CMD_PRIVATE3_VERSION: - ctl->val[0]=PRIVATE3_VERSION; + ctl->val[0] = PRIVATE3_VERSION; //private3 version + ctl->val[1] = MAJOR_VER; //major driver version + ctl->val[2] = MINOR_VER; //minor driver version + ctl->val[3] = card->is_audigy; //1=card is audigy + + if (card->is_audigy) + ctl->val[4]=emu10k1_readfn0(card, 0x18); + if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl))) ret = -EFAULT; break; case CMD_AC97_BOOST: - if(ctl->val[0]) + if (ctl->val[0]) emu10k1_ac97_write(card->ac97, 0x18, 0x0); else emu10k1_ac97_write(card->ac97, 0x18, 0x0808); @@ -556,7 +558,7 @@ card->tankmem.size = size; - sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END); + sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS,(u32) size_reg, TAGLIST_END); emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0); } @@ -623,8 +625,13 @@ if (cmd == SOUND_MIXER_INFO) { mixer_info info; - strncpy(info.id, card->ac97->name, sizeof(info.id)); - strncpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name)); + strlcpy(info.id, card->ac97->name, sizeof(info.id)); + + if (card->is_audigy) + strlcpy(info.name, "Audigy - Emu10k1", sizeof(info.name)); + else + strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name)); + info.modify_counter = card->ac97->modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/passthrough.c linux-2.6.0-test1/sound/oss/emu10k1/passthrough.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/passthrough.c 2003-07-14 05:34:01.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/passthrough.c 2003-07-15 03:11:58.000000000 +0200 @@ -109,7 +109,7 @@ return 0; } -static int pt_setup(struct emu10k1_wavedevice *wave_dev) +int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev) { u32 bits; struct emu10k1_card *card = wave_dev->card; @@ -155,7 +155,7 @@ pt->prepend_size = 0; if (pt->buf == NULL) return -ENOMEM; - pt_setup(wave_dev); + emu10k1_pt_setup(wave_dev); } if (pt->prepend_size) { int needed = PT_BLOCKSIZE - pt->prepend_size; @@ -208,13 +208,14 @@ if (pt->state != PT_STATE_INACTIVE) { DPF(2, "digital pass-through stopped\n"); - sblive_writeptr(card, GPR_BASE + pt->enable_gpr, 0, 0); + sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 0); for (i = 0; i < 3; i++) { if (pt->spcs_to_use & (1 << i)) sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]); } pt->state = PT_STATE_INACTIVE; - kfree(pt->buf); + if(pt->buf) + kfree(pt->buf); } } diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/passthrough.h linux-2.6.0-test1/sound/oss/emu10k1/passthrough.h --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/passthrough.h 2003-07-14 05:34:32.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/passthrough.h 2003-07-15 03:11:58.000000000 +0200 @@ -63,7 +63,36 @@ spinlock_t lock; }; +/* + Passthrough can be done in two methods: + + Method 1 : tram + In original emu10k1, we couldn't bypass the sample rate converters. Even at 48kHz + (the internal sample rate of the emu10k1) the samples would get messed up. + To over come this, samples are copied into the tram and a special dsp patch copies + the samples out and generates interrupts when a block has finnished playing. + + Method 2 : Interpolator bypass + + Creative fixed the sample rate convert problem in emu10k1 rev 7 and higher + (including the emu10k2 (audigy)). This allows us to use the regular, and much simpler + playback method. + + + In both methods, dsp code is used to mux audio and passthrough. This ensures that the spdif + doesn't receive audio and pasthrough data at the same time. The spdif flag SPCS_NOTAUDIODATA + is set to tell + + */ + +// emu10k1 revs greater than or equal to 7 can use method2 + +#define USE_PT_METHOD2 (card->is_audigy) +#define USE_PT_METHOD1 !USE_PT_METHOD2 + ssize_t emu10k1_pt_write(struct file *file, const char *buf, size_t count); + +int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev); void emu10k1_pt_stop(struct emu10k1_card *card); void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev); diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/recmgr.c linux-2.6.0-test1/sound/oss/emu10k1/recmgr.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/recmgr.c 2003-07-14 05:39:35.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/recmgr.c 2003-07-15 03:11:58.000000000 +0200 @@ -74,7 +74,7 @@ DPF(2, "recording source: AC97\n"); buffer->sizereg = ADCBS; buffer->addrreg = ADCBA; - buffer->idxreg = ADCIDX_IDX; + buffer->idxreg = card->is_audigy ? A_ADCIDX_IDX : ADCIDX_IDX; switch (wiinst->format.samplingrate) { case 0xBB80: @@ -95,21 +95,27 @@ case 0x3E80: buffer->adcctl = ADCCR_SAMPLERATE_16; break; + // FIXME: audigy supports 12kHz recording + /* + case ????: + buffer->adcctl = A_ADCCR_SAMPLERATE_12; + break; + */ case 0x2B11: - buffer->adcctl = ADCCR_SAMPLERATE_11; + buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_11 : ADCCR_SAMPLERATE_11; break; case 0x1F40: - buffer->adcctl = ADCCR_SAMPLERATE_8; + buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_8 : ADCCR_SAMPLERATE_8; break; default: BUG(); break; } - buffer->adcctl |= ADCCR_LCHANENABLE; + buffer->adcctl |= card->is_audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE; if (wiinst->format.channels == 2) - buffer->adcctl |= ADCCR_RCHANENABLE; + buffer->adcctl |= card->is_audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE; break; diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/voicemgr.c linux-2.6.0-test1/sound/oss/emu10k1/voicemgr.c --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/voicemgr.c 2003-07-14 05:34:43.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/voicemgr.c 2003-07-15 03:11:58.000000000 +0200 @@ -32,6 +32,34 @@ #include "voicemgr.h" #include "8010.h" +#define PITCH_48000 0x00004000 +#define PITCH_96000 0x00008000 +#define PITCH_85000 0x00007155 +#define PITCH_80726 0x00006ba2 +#define PITCH_67882 0x00005a82 +#define PITCH_57081 0x00004c1c + +u32 emu10k1_select_interprom(struct emu10k1_card *card, struct emu_voice *voice) +{ + if(voice->pitch_target==PITCH_48000) + return CCCA_INTERPROM_0; + else if(voice->pitch_targetpitch_target>=PITCH_96000) + return CCCA_INTERPROM_0; + else if(voice->pitch_target>=PITCH_85000) + return CCCA_INTERPROM_6; + else if(voice->pitch_target>=PITCH_80726) + return CCCA_INTERPROM_5; + else if(voice->pitch_target>=PITCH_67882) + return CCCA_INTERPROM_4; + else if(voice->pitch_target>=PITCH_57081) + return CCCA_INTERPROM_3; + else + return CCCA_INTERPROM_2; +} + + /** * emu10k1_voice_alloc_buffer - * @@ -216,17 +244,25 @@ voice->start += start; for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { - sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16); + if (card->is_audigy) { + sblive_writeptr(card, A_FXRT1, voice->num + i, voice->params[i].send_routing); + sblive_writeptr(card, A_FXRT2, voice->num + i, voice->params[i].send_routing2); + sblive_writeptr(card, A_SENDAMOUNTS, voice->num + i, voice->params[i].send_hgfe); + } else { + sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16); + } /* Stop CA */ /* Assumption that PT is already 0 so no harm overwriting */ - sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b); + sblive_writeptr(card, PTRX, voice->num + i, ((voice->params[i].send_dcba & 0xff) << 8) + | ((voice->params[i].send_dcba & 0xff00) >> 8)); sblive_writeptr_tag(card, voice->num + i, /* CSL, ST, CA */ - DSL, voice->endloop | (voice->params[i].send_d << 24), - PSST, voice->startloop | (voice->params[i].send_c << 24), - CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT), + DSL, voice->endloop | (voice->params[i].send_dcba & 0xff000000), + PSST, voice->startloop | ((voice->params[i].send_dcba & 0x00ff0000) << 8), + CCCA, (voice->start) | emu10k1_select_interprom(card,voice) | + ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT), /* Clear filter delay memory */ Z1, 0, Z2, 0, diff -urN -x '*~' -x '.*' -x '*.o' -x '*.mod.c' -x '*.ko' linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/voicemgr.h linux-2.6.0-test1/sound/oss/emu10k1/voicemgr.h --- linux-2.6.0-test1-vanilla-emu10k1-not-fixed/sound/oss/emu10k1/voicemgr.h 2003-07-14 05:34:43.000000000 +0200 +++ linux-2.6.0-test1/sound/oss/emu10k1/voicemgr.h 2003-07-15 03:11:58.000000000 +0200 @@ -48,11 +48,13 @@ /* FX bus amount send */ u32 send_routing; + // audigy only: + u32 send_routing2; + + u32 send_dcba; + // audigy only: + u32 send_hgfe; - u32 send_a; - u32 send_b; - u32 send_c; - u32 send_d; u32 initial_fc; u32 fc_target; --IiVenqGWf+H9Y6IX--