Commit 80e38dd5 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] emu10k further updates/bug fixes

parent ebf09724
/* /*
********************************************************************** **********************************************************************
* 8010.h * 8010.h
* Copyright 1999, 2000 Creative Labs, Inc. * Copyright 1999-2001 Creative Labs, Inc.
* *
********************************************************************** **********************************************************************
* *
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS * November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS
* line endings * line endings
* December 8, 1999 Jon Taylor Added lots of new register info * 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 @@ ...@@ -39,6 +41,14 @@
#include <linux/types.h> #include <linux/types.h>
// 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 = <val> + PCIBASE0 */ /* PCI function 0 registers, address = <val> + PCIBASE0 */
/************************************************************************************************/ /************************************************************************************************/
...@@ -57,6 +67,11 @@ ...@@ -57,6 +67,11 @@
#define IPR 0x08 /* Global interrupt pending register */ #define IPR 0x08 /* Global interrupt pending register */
/* Clear pending interrupts by writing a 1 to */ /* Clear pending interrupts by writing a 1 to */
/* the relevant bits and zero to the other bits */ /* 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_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */
#define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */ #define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */
#define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */ #define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */
...@@ -81,6 +96,10 @@ ...@@ -81,6 +96,10 @@
/* IP is written with CL set, the bit in CLIPL */ /* IP is written with CL set, the bit in CLIPL */
/* or CLIPH corresponding to the CIN value */ /* or CLIPH corresponding to the CIN value */
/* written will be cleared. */ /* 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 0x0c /* Interrupt enable register */
#define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */ #define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */
...@@ -108,6 +127,11 @@ ...@@ -108,6 +127,11 @@
/* behavior and possibly random segfaults and */ /* behavior and possibly random segfaults and */
/* lockups if enabled. */ /* 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 */ #define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */
/* NOTE: This bit must always be enabled */ /* NOTE: This bit must always be enabled */
#define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */ #define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */
...@@ -124,6 +148,10 @@ ...@@ -124,6 +148,10 @@
#define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */ #define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */
#define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-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 0x10 /* Wall Clock register */
#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */ #define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */
#define WC_SAMPLECOUNTER 0x14060010 #define WC_SAMPLECOUNTER 0x14060010
...@@ -186,6 +214,8 @@ ...@@ -186,6 +214,8 @@
/* Should be set to 1 when the EMU10K1 is */ /* Should be set to 1 when the EMU10K1 is */
/* completely initialized. */ /* completely initialized. */
//For Audigy, MPU port move to 0x70-0x74 ptr register
#define MUDATA 0x18 /* MPU401 data register (8 bits) */ #define MUDATA 0x18 /* MPU401 data register (8 bits) */
#define MUCMD 0x19 /* MPU401 command register (8 bits) */ #define MUCMD 0x19 /* MPU401 command register (8 bits) */
...@@ -197,13 +227,16 @@ ...@@ -197,13 +227,16 @@
#define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */ #define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */
#define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */ #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 */ /* NOTE: After the rate is changed, a maximum */
/* of 1024 sample periods should be allowed */ /* of 1024 sample periods should be allowed */
/* before the new rate is guaranteed accurate. */ /* 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 */ /* 0 == 1024 periods, [1..4] are not useful */
#define TIMER_RATE 0x0a00001a
#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */ #define AC97DATA 0x1c /* AC97 register set data register (16 bit) */
...@@ -386,6 +419,8 @@ ...@@ -386,6 +419,8 @@
#define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */ #define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */
#define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */ #define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */
/* Signed 2's complement, with +/- 12dB extremes */ /* 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 0x1d /* Vibrato amount and vibrato LFO frequency register */
#define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */ #define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */
...@@ -426,7 +461,12 @@ ...@@ -426,7 +461,12 @@
#define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */ #define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */
/* NOTE: To guarantee phase coherency, both channels */ /* NOTE: To guarantee phase coherency, both channels */
/* must be disabled prior to enabling 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_MASK 0x00000007 /* Sample rate convertor output rate */
#define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */ #define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */
#define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */ #define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */
#define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */ #define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */
...@@ -436,10 +476,16 @@ ...@@ -436,10 +476,16 @@
#define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */ #define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */
#define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz 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 */ #define FXWC 0x43 /* FX output write channels register */
/* When set, each bit enables the writing of the */ /* 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 0x44 /* Tank cache buffer size register */
#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ #define TCBS_MASK 0x00000007 /* Tank cache buffer size field */
#define TCBS_BUFFSIZE_16K 0x00000000 #define TCBS_BUFFSIZE_16K 0x00000000
...@@ -519,6 +565,13 @@ ...@@ -519,6 +565,13 @@
#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ #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 SPCS0 0x54 /* SPDIF output Channel Status 0 register */
#define SPCS1 0x55 /* SPDIF output Channel Status 1 register */ #define SPCS1 0x55 /* SPDIF output Channel Status 1 register */
...@@ -582,10 +635,19 @@ ...@@ -582,10 +635,19 @@
#define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */
#define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ #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 0x63 /* Microphone recording buffer index register */
#define MICIDX_MASK 0x0000ffff /* 16-bit value */ #define MICIDX_MASK 0x0000ffff /* 16-bit value */
#define MICIDX_IDX 0x10000063 #define MICIDX_IDX 0x10000063
#define A_ADCIDX 0x63
#define A_ADCIDX_IDX 0x10000063
#define ADCIDX 0x64 /* ADC recording buffer index register */ #define ADCIDX 0x64 /* ADC recording buffer index register */
#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */ #define ADCIDX_MASK 0x0000ffff /* 16 bit index field */
#define ADCIDX_IDX 0x10000064 #define ADCIDX_IDX 0x10000064
...@@ -594,9 +656,50 @@ ...@@ -594,9 +656,50 @@
#define FXIDX_MASK 0x0000ffff /* 16-bit value */ #define FXIDX_MASK 0x0000ffff /* 16-bit value */
#define FXIDX_IDX 0x10000065 #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 */ /* Each FX general purpose register is 32 bits in length, all bits are used */
#define FXGPREGBASE 0x100 /* FX general purpose registers base */ #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 */ /* 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 */ /* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */
/* locations are for external TRAM. */ /* locations are for external TRAM. */
...@@ -621,4 +724,14 @@ ...@@ -621,4 +724,14 @@
#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */ #define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */
#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */ #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 */ #endif /* _8010_H */
...@@ -158,8 +158,8 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t ...@@ -158,8 +158,8 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t
spin_unlock_irqrestore(&woinst->lock, flags); spin_unlock_irqrestore(&woinst->lock, flags);
return -ENXIO; return -ENXIO;
} }
// This is for emu10k1 revs less than 7, we need to go through tram
if (woinst->format.passthrough) { if (woinst->format.passthrough == 1) {
int r; int r;
woinst->buffer.ossfragshift = PT_BLOCKSIZE_LOG2; woinst->buffer.ossfragshift = PT_BLOCKSIZE_LOG2;
...@@ -350,8 +350,9 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -350,8 +350,9 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
case SNDCTL_DSP_GETCAPS: case SNDCTL_DSP_GETCAPS:
DPF(2, "SNDCTL_DSP_GETCAPS:\n"); 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: case SNDCTL_DSP_SPEED:
DPF(2, "SNDCTL_DSP_SPEED:\n"); DPF(2, "SNDCTL_DSP_SPEED:\n");
...@@ -528,8 +529,8 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -528,8 +529,8 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
else if (file->f_mode & FMODE_WRITE) { else if (file->f_mode & FMODE_WRITE) {
val = AFMT_S16_LE | AFMT_U8; val = AFMT_S16_LE | AFMT_U8;
if (emu10k1_find_control_gpr(&wave_dev->card->mgr, if (emu10k1_find_control_gpr(&wave_dev->card->mgr,
wave_dev->card->pt.patch_name, wave_dev->card->pt.patch_name,
wave_dev->card->pt.enable_gpr_name) >= 0) wave_dev->card->pt.enable_gpr_name) >= 0)
val |= AFMT_AC3; val |= AFMT_AC3;
} }
return put_user(val, (int *) arg); return put_user(val, (int *) arg);
...@@ -789,7 +790,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -789,7 +790,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
cinfo.blocks = 0; cinfo.blocks = 0;
} }
if(wiinst->mmapped) if (wiinst->mmapped)
wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size; wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size;
spin_unlock_irqrestore(&wiinst->lock, flags); spin_unlock_irqrestore(&wiinst->lock, flags);
...@@ -811,15 +812,17 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -811,15 +812,17 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
spin_lock_irqsave(&woinst->lock, flags); spin_lock_irqsave(&woinst->lock, flags);
if (woinst->state & WAVE_STATE_OPEN || 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; int num_fragments;
if (woinst->format.passthrough) {
if (woinst->format.passthrough == 1) {
emu10k1_pt_waveout_update(wave_dev); emu10k1_pt_waveout_update(wave_dev);
cinfo.bytes = woinst->total_played; cinfo.bytes = woinst->total_played;
} else { } else {
emu10k1_waveout_update(woinst); emu10k1_waveout_update(woinst);
cinfo.bytes = woinst->total_played; cinfo.bytes = woinst->total_played;
} }
cinfo.ptr = woinst->buffer.hw_pos; cinfo.ptr = woinst->buffer.hw_pos;
num_fragments = cinfo.bytes / woinst->buffer.fragment_size; num_fragments = cinfo.bytes / woinst->buffer.fragment_size;
cinfo.blocks = num_fragments - woinst->blocks; cinfo.blocks = num_fragments - woinst->blocks;
...@@ -899,7 +902,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -899,7 +902,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
if (file->f_mode & FMODE_WRITE) { if (file->f_mode & FMODE_WRITE) {
/* digital pass-through fragment count and size are fixed values */ /* 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 */ return -EINVAL; /* too late to change */
woinst->buffer.ossfragshift = val & 0xffff; woinst->buffer.ossfragshift = val & 0xffff;
...@@ -936,19 +939,35 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -936,19 +939,35 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
kfree (buf); kfree (buf);
return -EINVAL; return -EINVAL;
} }
if (buf->command == CMD_WRITE) {
#ifdef DBGEMU #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 #else
if ( ((buf->offs < 0x100 ) || (buf->offs + buf->len > 0x800) || (buf->len > 1000)) if (((buf->offs < 0x100) || (buf->offs + buf->len > (wave_dev->card->is_audigy ? 0xe00 : 0x800)) || (buf->len > 1000)
&& !( ( buf->offs == DBG) && (buf->len ==1) )){ ) && !(
#endif //any register allowed raw access to users goes here:
kfree(buf); (buf->offs == DBG ||
return -EINVAL; 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) { if (buf->command == CMD_READ) {
for (i = 0; i < buf->len; i++) 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))) { if (copy_to_user((copr_buffer *) arg, buf, sizeof(copr_buffer))) {
kfree(buf); kfree(buf);
...@@ -956,7 +975,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -956,7 +975,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
} }
} else { } else {
for (i = 0; i < buf->len; i++) 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); kfree (buf);
...@@ -1244,8 +1263,9 @@ static int emu10k1_audio_release(struct inode *inode, struct file *file) ...@@ -1244,8 +1263,9 @@ static int emu10k1_audio_release(struct inode *inode, struct file *file)
struct woinst *woinst = wave_dev->woinst; struct woinst *woinst = wave_dev->woinst;
spin_lock_irqsave(&woinst->lock, flags); spin_lock_irqsave(&woinst->lock, flags);
if(woinst->format.passthrough==2)
if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE) { card->pt.state=PT_STATE_PLAYING;
if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE){
spin_lock(&card->pt.lock); spin_lock(&card->pt.lock);
emu10k1_pt_stop(card); emu10k1_pt_stop(card);
spin_unlock(&card->pt.lock); spin_unlock(&card->pt.lock);
......
...@@ -113,7 +113,7 @@ int emu10k1_mpuin_close(struct emu10k1_card *card) ...@@ -113,7 +113,7 @@ int emu10k1_mpuin_close(struct emu10k1_card *card)
} }
/* Disable RX interrupt */ /* 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); emu10k1_mpu_release(card);
...@@ -189,7 +189,7 @@ int emu10k1_mpuin_start(struct emu10k1_card *card) ...@@ -189,7 +189,7 @@ int emu10k1_mpuin_start(struct emu10k1_card *card)
card_mpuin->qhead = 0; card_mpuin->qhead = 0;
card_mpuin->qtail = 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; return 0;
...@@ -207,7 +207,7 @@ int emu10k1_mpuin_stop(struct emu10k1_card *card) ...@@ -207,7 +207,7 @@ int emu10k1_mpuin_stop(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuin_stop()\n"); 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 */ card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
...@@ -246,7 +246,7 @@ int emu10k1_mpuin_reset(struct emu10k1_card *card) ...@@ -246,7 +246,7 @@ int emu10k1_mpuin_reset(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuin_reset()\n"); 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) { while (card_mpuin->firstmidiq) {
midiq = card_mpuin->firstmidiq; midiq = card_mpuin->firstmidiq;
......
...@@ -72,7 +72,7 @@ int emu10k1_mpuout_close(struct emu10k1_card *card) ...@@ -72,7 +72,7 @@ int emu10k1_mpuout_close(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuout_close()\n"); 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); spin_lock_irqsave(&card_mpuout->lock, flags);
...@@ -142,7 +142,7 @@ int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihd ...@@ -142,7 +142,7 @@ int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihd
card_mpuout->intr = 0; 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); spin_unlock_irqrestore(&card_mpuout->lock, flags);
...@@ -206,7 +206,7 @@ void emu10k1_mpuout_bh(unsigned long refdata) ...@@ -206,7 +206,7 @@ void emu10k1_mpuout_bh(unsigned long refdata)
if ((card_mpuout->firstmidiq != NULL) || cByteSent) { if ((card_mpuout->firstmidiq != NULL) || cByteSent) {
card_mpuout->intr = 0; 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); spin_unlock_irqrestore(&card_mpuout->lock, flags);
...@@ -221,7 +221,7 @@ int emu10k1_mpuout_irqhandler(struct emu10k1_card *card) ...@@ -221,7 +221,7 @@ int emu10k1_mpuout_irqhandler(struct emu10k1_card *card)
DPF(4, "emu10k1_mpuout_irqhandler\n"); DPF(4, "emu10k1_mpuout_irqhandler\n");
card_mpuout->intr = 1; 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); tasklet_hi_schedule(&card_mpuout->tasklet);
......
...@@ -85,25 +85,36 @@ static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format ...@@ -85,25 +85,36 @@ static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format
break; break;
} }
if (do_passthrough) { 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 */ /* 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 || card->pt.state != PT_STATE_INACTIVE ||
(wave_fmt->samplingrate != 48000 && !is_ac3) ||
(wave_fmt->samplingrate != 48000 && !is_ac3)) { (wave_fmt->samplingrate != 48000 && !is_ac3)) {
DPF(2, "unable to set pass-through mode\n"); DPF(2, "unable to set pass-through mode\n");
} else { } else if (USE_PT_METHOD1) {
wave_fmt->samplingrate = 48000; i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name);
wave_fmt->channels = 2; j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name);
wave_fmt->passthrough = 1; if (i < 0 || j < 0)
card->pt.intr_gpr = i; DPF(2, "unable to set pass-through mode\n");
card->pt.enable_gpr = j; else {
card->pt.state = PT_STATE_INACTIVE; wave_fmt->samplingrate = 48000;
card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.pos_gpr_name); wave_fmt->channels = 2;
DPD(2, "is_ac3 is %d\n", is_ac3); card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
card->pt.ac3data = is_ac3; card->pt.pos_gpr_name);
wave_fmt->bitsperchannel = 16; 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 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned ...@@ -149,33 +160,37 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample; voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample;
voice->start = voice->startloop; voice->start = voice->startloop;
if (voice->flags & VOICE_FLAGS_STEREO) {
voice->params[0].send_a = card->waveout.send_a[1]; voice->params[0].volume_target = 0xffff;
voice->params[0].send_b = card->waveout.send_b[1]; voice->params[0].initial_fc = 0xff;
voice->params[0].send_c = card->waveout.send_c[1]; voice->params[0].initial_attn = 0x00;
voice->params[0].send_d = card->waveout.send_d[1]; voice->params[0].byampl_env_sustain = 0x7f;
voice->params[0].byampl_env_decay = 0x7f;
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];
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].volume_target = 0xffff;
voice->params[1].initial_fc = 0xff; voice->params[1].initial_fc = 0xff;
voice->params[1].initial_attn = 0x00; voice->params[1].initial_attn = 0x00;
...@@ -183,30 +198,28 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned ...@@ -183,30 +198,28 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
voice->params[1].byampl_env_decay = 0x7f; voice->params[1].byampl_env_decay = 0x7f;
} else { } else {
if (woinst->num_voices > 1) { if (woinst->num_voices > 1) {
voice->params[0].send_a = 0xff; // Multichannel pcm
voice->params[0].send_b = 0; voice->params[0].send_dcba=0xff;
voice->params[0].send_c = 0; voice->params[0].send_hgfe=0;
voice->params[0].send_d = 0; if (card->is_audigy) {
voice->params[0].send_routing = 0x3f3f3f00 + card->mchannel_fx + voicenum;
voice->params[0].send_routing = voice->params[0].send_routing2 = 0x3f3f3f3f;
0xfff0 + card->mchannel_fx + voicenum; } else {
voice->params[0].send_routing = 0xfff0 + card->mchannel_fx + voicenum;
}
} else { } else {
voice->params[0].send_a = card->waveout.send_a[0]; voice->params[0].send_dcba = card->waveout.send_dcba[SEND_MONO];
voice->params[0].send_b = card->waveout.send_b[0]; voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_MONO];
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 = card->waveout.send_routing[ROUTE_PCM1];
if (woinst->device) voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
voice->params[0].send_routing = 0x7654; } else {
else voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM];
voice->params[0].send_routing = card->waveout.send_routing[0]; voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
} }
}
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;
} }
DPD(2, "voice: startloop=%#x, endloop=%#x\n", voice->startloop, voice->endloop); DPD(2, "voice: startloop=%#x, endloop=%#x\n", voice->startloop, voice->endloop);
...@@ -280,9 +293,16 @@ void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev) ...@@ -280,9 +293,16 @@ void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
{ {
struct emu10k1_card *card = wave_dev->card; struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst; struct woinst *woinst = wave_dev->woinst;
struct pt_data *pt = &card->pt;
DPF(2, "emu10k1_waveout_start()\n"); 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 */ /* Actual start */
emu10k1_voices_start(woinst->voice, woinst->num_voices, woinst->total_played); emu10k1_voices_start(woinst->voice, woinst->num_voices, woinst->total_played);
......
...@@ -80,15 +80,20 @@ void emu10k1_set_control_gpr(struct emu10k1_card *card, int addr, s32 val, int f ...@@ -80,15 +80,20 @@ void emu10k1_set_control_gpr(struct emu10k1_card *card, int addr, s32 val, int f
if (addr < 0 || addr >= NUM_GPRS) if (addr < 0 || addr >= NUM_GPRS)
return; return;
if (flag) //fixme: once patch manager is up, remember to fix this for the audigy
val += sblive_readptr(card, GPR_BASE + addr, 0); if (card->is_audigy) {
sblive_writeptr(card, A_GPR_BASE + addr, 0, val);
if (val > mgr->gpr[addr].max) } else {
val = mgr->gpr[addr].max; if (flag)
else if (val < mgr->gpr[addr].min) val += sblive_readptr(card, GPR_BASE + addr, 0);
val = mgr->gpr[addr].min; if (val > mgr->gpr[addr].max)
val = mgr->gpr[addr].max;
sblive_writeptr(card, GPR_BASE + addr, 0, val); else if (val < mgr->gpr[addr].min)
val = mgr->gpr[addr].min;
sblive_writeptr(card, GPR_BASE + addr, 0, val);
}
} }
//TODO: make this configurable: //TODO: make this configurable:
......
...@@ -32,16 +32,30 @@ ...@@ -32,16 +32,30 @@
#ifndef _EFXMGR_H #ifndef _EFXMGR_H
#define _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) \ #define OP(op, z, w, x, y) \
do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \ do { WRITE_EFX(card, (pc) * 2, ((x) << emu_efx_info[card->is_audigy].high_operand_shift) | (y)); \
WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \ 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) ++pc; } while (0)
#define NUM_INPUTS 0x20 #define NUM_INPUTS 0x20
#define NUM_OUTPUTS 0x20 #define NUM_OUTPUTS 0x20
#define NUM_GPRS 0x100 #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 GPR_NAME_SIZE 32
#define PATCH_NAME_SIZE 32 #define PATCH_NAME_SIZE 32
...@@ -98,6 +112,9 @@ enum { ...@@ -98,6 +112,9 @@ enum {
#define GPR_BASE 0x100 #define GPR_BASE 0x100
#define OUTPUT_BASE 0x20 #define OUTPUT_BASE 0x20
#define A_GPR_BASE 0x400
#define A_OUTPUT_BASE 0x60
#define MAX_PATCHES_PAGES 32 #define MAX_PATCHES_PAGES 32
struct patch_manager { struct patch_manager {
......
...@@ -160,6 +160,24 @@ void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data) ...@@ -160,6 +160,24 @@ void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data)
return; 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 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
{ {
u32 val; u32 val;
...@@ -200,12 +218,13 @@ void emu10k1_timer_set(struct emu10k1_card * card, u16 data) ...@@ -200,12 +218,13 @@ void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
* write/read Emu10k1 pointer-offset register set, accessed through * * write/read Emu10k1 pointer-offset register set, accessed through *
* the PTR and DATA registers * * the PTR and DATA registers *
*************************************************************************/ *************************************************************************/
#define A_PTR_ADDRESS_MASK 0x0fff0000
void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data) void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
{ {
u32 regptr; u32 regptr;
unsigned long flags; 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) { if (reg & 0xff000000) {
u32 mask; u32 mask;
...@@ -242,7 +261,7 @@ void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...) ...@@ -242,7 +261,7 @@ void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
while ((reg = va_arg(args, u32)) != TAGLIST_END) { while ((reg = va_arg(args, u32)) != TAGLIST_END) {
u32 data = va_arg(args, u32); 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)); | (channel & PTR_CHANNELNUM_MASK));
outl(regptr, card->iobase + PTR); outl(regptr, card->iobase + PTR);
if (reg & 0xff000000) { if (reg & 0xff000000) {
...@@ -267,7 +286,7 @@ u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel) ...@@ -267,7 +286,7 @@ u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
u32 regptr, val; u32 regptr, val;
unsigned long flags; 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) { if (reg & 0xff000000) {
u32 mask; u32 mask;
...@@ -389,7 +408,7 @@ void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value) ...@@ -389,7 +408,7 @@ void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value)
outb(reg, card->iobase + AC97ADDRESS); outb(reg, card->iobase + AC97ADDRESS);
outw(value, card->iobase + AC97DATA); outw(value, card->iobase + AC97DATA);
outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
} }
...@@ -402,15 +421,23 @@ int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data) ...@@ -402,15 +421,23 @@ int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
unsigned long flags; unsigned long flags;
int ret; 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) { if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
outb(data, card->iobase + MUDATA); outb(data, card->iobase + MUDATA);
ret = 0; ret = 0;
} else } else
ret = -1; ret = -1;
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
}
return ret; return ret;
} }
...@@ -420,15 +447,23 @@ int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data) ...@@ -420,15 +447,23 @@ int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
unsigned long flags; unsigned long flags;
int ret; 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) { if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
*data = inb(card->iobase + MUDATA); *data = inb(card->iobase + MUDATA);
ret = 0; ret = 0;
} else } else
ret = -1; ret = -1;
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
}
return ret; return ret;
} }
...@@ -439,37 +474,54 @@ int emu10k1_mpu_reset(struct emu10k1_card *card) ...@@ -439,37 +474,54 @@ int emu10k1_mpu_reset(struct emu10k1_card *card)
unsigned long flags; unsigned long flags;
DPF(2, "emu10k1_mpu_reset()\n"); 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) { return 0;
spin_lock_irqsave(&card->lock, flags); } else {
outb(MUCMD_RESET, card->iobase + MUCMD); if (card->mpuacqcount == 0) {
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); spin_lock_irqsave(&card->lock, flags);
outb(MUCMD_RESET, card->iobase + MUCMD); outb(MUCMD_RESET, card->iobase + MUCMD);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
sblive_wcwait(card, 8); sblive_wcwait(card, 8);
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD); outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
sblive_wcwait(card, 8); sblive_wcwait(card, 8);
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
status = inb(card->iobase + MUDATA); status = inb(card->iobase + MUDATA);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
if (status == 0xfe) if (status == 0xfe)
return 0; return 0;
else else
return -1; return -1;
} }
return 0; return 0;
}
} }
int emu10k1_mpu_acquire(struct emu10k1_card *card) int emu10k1_mpu_acquire(struct emu10k1_card *card)
......
...@@ -79,13 +79,21 @@ struct memhandle ...@@ -79,13 +79,21 @@ struct memhandle
struct emu10k1_waveout struct emu10k1_waveout
{ {
u16 send_routing[3]; u32 send_routing[3];
// audigy only:
u32 send_routing2[3];
u8 send_a[3]; u32 send_dcba[3];
u8 send_b[3]; // audigy only:
u8 send_c[3]; u32 send_hgfe[3];
u8 send_d[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 struct emu10k1_wavein
{ {
...@@ -129,7 +137,7 @@ struct mixer_private_ioctl { ...@@ -129,7 +137,7 @@ struct mixer_private_ioctl {
#define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl) #define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl)
//up this number when breaking compatibility //up this number when breaking compatibility
#define PRIVATE3_VERSION 1 #define PRIVATE3_VERSION 2
struct emu10k1_card struct emu10k1_card
{ {
...@@ -181,7 +189,7 @@ struct emu10k1_card ...@@ -181,7 +189,7 @@ struct emu10k1_card
u32 has_toslink; // TOSLink detection u32 has_toslink; // TOSLink detection
u8 chiprev; /* Chip revision */ u8 chiprev; /* Chip revision */
u8 is_audigy;
u8 is_aps; u8 is_aps;
struct patch_manager mgr; struct patch_manager mgr;
...@@ -211,6 +219,7 @@ extern struct list_head emu10k1_devs; ...@@ -211,6 +219,7 @@ extern struct list_head emu10k1_devs;
/* Hardware Abstraction Layer access functions */ /* Hardware Abstraction Layer access functions */
void emu10k1_writefn0(struct emu10k1_card *, u32, u32); 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); u32 emu10k1_readfn0(struct emu10k1_card *, u32);
void emu10k1_timer_set(struct emu10k1_card *, u16); void emu10k1_timer_set(struct emu10k1_card *, u16);
......
...@@ -33,15 +33,15 @@ ...@@ -33,15 +33,15 @@
#define _IRQ_H #define _IRQ_H
/* EMU Irq Types */ /* EMU Irq Types */
#define IRQTYPE_PCIBUSERROR IPR_PCIERROR #define IRQTYPE_PCIBUSERROR IPR_PCIERROR
#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE) #define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK) #define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL) #define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
#define IRQTYPE_MPUOUT IPR_MIDITRANSBUFEMPTY #define IRQTYPE_MPUOUT (IPR_MIDITRANSBUFEMPTY | A_IPR_MIDITRANSBUFEMPTY2)
#define IRQTYPE_MPUIN IPR_MIDIRECVBUFEMPTY #define IRQTYPE_MPUIN (IPR_MIDIRECVBUFEMPTY | A_IPR_MIDIRECVBUFEMPTY2)
#define IRQTYPE_TIMER IPR_INTERVALTIMER #define IRQTYPE_TIMER IPR_INTERVALTIMER
#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE) #define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
#define IRQTYPE_DSP IPR_FXDSP #define IRQTYPE_DSP IPR_FXDSP
void emu10k1_timer_irqhandler(struct emu10k1_card *); void emu10k1_timer_irqhandler(struct emu10k1_card *);
void emu10k1_dsp_irqhandler(struct emu10k1_card *); void emu10k1_dsp_irqhandler(struct emu10k1_card *);
......
...@@ -78,10 +78,11 @@ ...@@ -78,10 +78,11 @@
* Cleaned up poll() functions (audio and midi). Don't start input. * Cleaned up poll() functions (audio and midi). Don't start input.
* Restrict DMA pages used to 512Mib range. * Restrict DMA pages used to 512Mib range.
* New AC97_BOOST mixer ioctl. * 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. * Fix recording buffering parameters calculation.
* Use unsigned long for variables in bit ops. * 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) * Fixed timer rate setting (it's a 16-bit register)
*********************************************************************/ *********************************************************************/
...@@ -114,7 +115,6 @@ ...@@ -114,7 +115,6 @@
#define SNDCARD_EMU10K1 46 #define SNDCARD_EMU10K1 46
#endif #endif
#define DRIVER_VERSION "0.20"
/* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */ /* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */
#define EMU10K1_DMA_MASK 0x1fffffff /* DMA buffer mask for pci_alloc_consist */ #define EMU10K1_DMA_MASK 0x1fffffff /* DMA buffer mask for pci_alloc_consist */
...@@ -126,20 +126,27 @@ ...@@ -126,20 +126,27 @@
#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1 #ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1
#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
#endif #endif
#ifndef PCI_DEVICE_ID_CREATIVE_AUDIGY
#define PCI_DEVICE_ID_CREATIVE_AUDIGY 0x0004
#endif
#define EMU_APS_SUBID 0x40011102 #define EMU_APS_SUBID 0x40011102
enum { enum {
EMU10K1 = 0, EMU10K1 = 0,
AUDIGY,
}; };
static char *card_names[] __devinitdata = { static char *card_names[] __devinitdata = {
"EMU10K1", "EMU10K1",
"Audigy",
}; };
static struct pci_device_id emu10k1_pci_tbl[] = { static struct pci_device_id emu10k1_pci_tbl[] = {
{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 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,} {0,}
}; };
...@@ -160,6 +167,67 @@ static struct midi_operations emu10k1_midi_operations; ...@@ -160,6 +167,67 @@ static struct midi_operations emu10k1_midi_operations;
extern irqreturn_t emu10k1_interrupt(int, void *, struct pt_regs *s); extern irqreturn_t emu10k1_interrupt(int, void *, struct pt_regs *s);
static int __devinit emu10k1_audio_init(struct emu10k1_card *card) 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); card->audio_dev = register_sound_dsp(&emu10k1_audio_fops, -1);
if (card->audio_dev < 0) { if (card->audio_dev < 0) {
...@@ -173,56 +241,167 @@ static int __devinit emu10k1_audio_init(struct emu10k1_card *card) ...@@ -173,56 +241,167 @@ static int __devinit emu10k1_audio_init(struct emu10k1_card *card)
goto err_dev1; goto err_dev1;
} }
/* Assign default playback voice parameters */ card->ac97->dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1);
card->mchannel_fx = 8; if (card->ac97->dev_mixer < 0) {
/* mono voice */ printk(KERN_ERR "emu10k1: cannot register mixer device\n");
card->waveout.send_a[0] = 0xff; goto err_mixer;
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;
/* Assign default recording parameters */ card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1);
/* FIXME */ if (card->midi_dev < 0) {
if (card->is_aps) printk(KERN_ERR "emu10k1: cannot register midi device!\n");
card->wavein.recsrc = WAVERECORD_FX; goto err_midi;
else }
card->wavein.recsrc = WAVERECORD_AC97;
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; return 0;
err_midi:
unregister_sound_mixer(card->ac97->dev_mixer);
err_mixer:
unregister_sound_dsp(card->audio_dev);
err_dev1: err_dev1:
unregister_sound_dsp(card->audio_dev); unregister_sound_dsp(card->audio_dev);
err_dev: err_dev:
return -ENODEV; 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_dev1);
unregister_sound_dsp(card->audio_dev); 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[32]; 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[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(); struct ac97_codec *codec = ac97_alloc_codec();
if(codec == NULL) if(codec == NULL)
...@@ -231,15 +410,6 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) ...@@ -231,15 +410,6 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
return -EIO; return -EIO;
} }
card->ac97 = codec; 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; card->ac97->private_data = card;
if (!card->is_aps) { if (!card->is_aps) {
...@@ -261,23 +431,6 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) ...@@ -261,23 +431,6 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
// Force 5bit: // Force 5bit:
//card->ac97->bit_resolution=5; //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 */ /* these will store the original values and never be modified */
card->ac97_supported_mixers = card->ac97->supported_mixers; card->ac97_supported_mixers = card->ac97->supported_mixers;
card->ac97_stereo_mixers = card->ac97->stereo_mixers; card->ac97_stereo_mixers = card->ac97->stereo_mixers;
...@@ -285,34 +438,13 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) ...@@ -285,34 +438,13 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
return 0; 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: err_out:
unregister_sound_mixer (card->ac97->dev_mixer);
err_codec:
ac97_release_codec(card->ac97); ac97_release_codec(card->ac97);
return -EIO; 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); ac97_release_codec(card->ac97);
} }
...@@ -320,13 +452,6 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card) ...@@ -320,13 +452,6 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card)
{ {
int ret; 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); card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL);
if (card->mpuout == NULL) { if (card->mpuout == NULL) {
printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n");
...@@ -366,31 +491,6 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card) ...@@ -366,31 +491,6 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card)
goto err_out3; 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; return 0;
err_out3: err_out3:
...@@ -398,28 +498,16 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card) ...@@ -398,28 +498,16 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card)
err_out2: err_out2:
kfree(card->mpuout); kfree(card->mpuout);
err_out1: err_out1:
unregister_sound_midi(card->midi_dev);
return ret; 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); tasklet_kill(&card->mpuout->tasklet);
kfree(card->mpuout); kfree(card->mpuout);
tasklet_kill(&card->mpuin->tasklet); tasklet_kill(&card->mpuin->tasklet);
kfree(card->mpuin); 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) static void __devinit voice_init(struct emu10k1_card *card)
...@@ -450,7 +538,7 @@ static void __devinit addxmgr_init(struct emu10k1_card *card) ...@@ -450,7 +538,7 @@ static void __devinit addxmgr_init(struct emu10k1_card *card)
card->emupagetable[1] = MAXPAGES - 1; card->emupagetable[1] = MAXPAGES - 1;
} }
static void __devinit fx_cleanup(struct patch_manager *mgr) static void fx_cleanup(struct patch_manager *mgr)
{ {
int i; int i;
for(i = 0; i < mgr->current_pages; i++) for(i = 0; i < mgr->current_pages; i++)
...@@ -465,24 +553,25 @@ static int __devinit fx_init(struct emu10k1_card *card) ...@@ -465,24 +553,25 @@ static int __devinit fx_init(struct emu10k1_card *card)
s32 left, right; s32 left, right;
int i; int i;
u32 pc = 0; 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++) { for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
mgr->ctrl_gpr[i][0] = -1; mgr->ctrl_gpr[i][0] = -1;
mgr->ctrl_gpr[i][1] = -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++) if (card->is_audigy)
sblive_writeptr_tag(card, 0, mgr->current_pages = (2 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE;
FXGPREGBASE + i, 0, else
TANKMEMADDRREGBASE + i, 0, /* !! The number below must equal the number of patches, currently 11 !! */
TAGLIST_END); mgr->current_pages = (11 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE;
/* !! The number bellow 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++) { for (i = 0; i < mgr->current_pages; i++) {
mgr->patch[i] = (void *)__get_free_page(GFP_KERNEL); mgr->patch[i] = (void *)__get_free_page(GFP_KERNEL);
if (mgr->patch[i] == NULL) { if (mgr->patch[i] == NULL) {
...@@ -493,215 +582,298 @@ static int __devinit fx_init(struct emu10k1_card *card) ...@@ -493,215 +582,298 @@ static int __devinit fx_init(struct emu10k1_card *card)
memset(mgr->patch[i], 0, PAGE_SIZE); memset(mgr->patch[i], 0, PAGE_SIZE);
} }
pc = 0; if (card->is_audigy) {
patch_n = 0; for (i = 0; i < 1024; i++)
//first free GPR = 0x11b OP(0xf, 0x0c0, 0x0c0, 0x0cf, 0x0c0);
/* 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); for (i = 0; i < 512 ; i++)
GET_OUTPUT_GPR(patch, 0x101, 0x1); sblive_writeptr(card, A_GPR_BASE+i,0,0);
GET_CONTROL_GPR(patch, 0x107, "Vol", 0, 0x7fffffff);
GET_DYNAMIC_GPR(patch, 0x112);
OP(4, 0x112, 0x40, PCM_IN_R, 0x44); pc=0;
OP(0, 0x101, 0x040, 0x112, 0x107);
INPUT_PATCH_END(patch); //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-Digital In Volume control // CD + PCM
INPUT_PATCH_START(patch, "CD-Digital Vol L", 0x12, 0); OP(6, 0x400, 0x0c0, 0x402, 0x404);
GET_OUTPUT_GPR(patch, 0x10c, 0x12); OP(6, 0x401, 0x0c0, 0x403, 0x405);
GET_CONTROL_GPR(patch, 0x10d, "Vol", 0, 0x7fffffff);
// Front Output + Master Volume
OP(0, 0x68, 0x0c0, 0x408, 0x400);
OP(0, 0x69, 0x0c0, 0x409, 0x401);
OP(0, 0x10c, 0x040, SPDIF_CD_L, 0x10d); // Add-in analog inputs for other speakers
INPUT_PATCH_END(patch); OP(6, 0x400, 0x40, 0x400, 0xc0);
OP(6, 0x401, 0x41, 0x401, 0xc0);
INPUT_PATCH_START(patch, "CD-Digital Vol R", 0x13, 0); // Digital Front + Master Volume
GET_OUTPUT_GPR(patch, 0x10e, 0x13); OP(0, 0x60, 0x0c0, 0x408, 0x400);
GET_CONTROL_GPR(patch, 0x10f, "Vol", 0, 0x7fffffff); OP(0, 0x61, 0x0c0, 0x409, 0x401);
OP(0, 0x10e, 0x040, SPDIF_CD_R, 0x10f); // Rear Output + Rear Volume
INPUT_PATCH_END(patch); OP(0, 0x06e, 0x0c0, 0x419, 0x400);
OP(0, 0x06f, 0x0c0, 0x41a, 0x401);
//Volume Correction for Multi-channel Inputs // Digital Rear Output + Rear Volume
INPUT_PATCH_START(patch, "Multi-Channel Gain", 0x08, 0); OP(0, 0x066, 0x0c0, 0x419, 0x400);
patch->input=patch->output=0x3F00; OP(0, 0x067, 0x0c0, 0x41a, 0x401);
GET_OUTPUT_GPR(patch, 0x113, MULTI_FRONT_L); // Audigy Drive, Headphone out
GET_OUTPUT_GPR(patch, 0x114, MULTI_FRONT_R); OP(6, 0x64, 0x0c0, 0x0c0, 0x400);
GET_OUTPUT_GPR(patch, 0x115, MULTI_REAR_L); OP(6, 0x65, 0x0c0, 0x0c0, 0x401);
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); // ac97 Recording
OP(4, 0x114, 0x40, MULTI_FRONT_R, 0x44); OP(6, 0x76, 0x0c0, 0x0c0, 0x40);
OP(4, 0x115, 0x40, MULTI_REAR_L, 0x44); OP(6, 0x77, 0x0c0, 0x0c0, 0x41);
OP(4, 0x116, 0x40, MULTI_REAR_R, 0x44);
OP(4, 0x117, 0x40, MULTI_CENTER, 0x44); // Center = sub = Left/2 + Right/2
OP(4, 0x118, 0x40, MULTI_LFE, 0x44); OP(0xe, 0x400, 0x401, 0xcd, 0x400);
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); // center/sub Volume (master)
GET_OUTPUT_GPR(rpatch, 0x105, 0x9); OP(0, 0x06a, 0x0c0, 0x408, 0x400);
GET_OUTPUT_GPR(rpatch, 0x10a, 0x2); OP(0, 0x06b, 0x0c0, 0x409, 0x400);
GET_OUTPUT_GPR(rpatch, 0x10b, 0x3);
// Digital center/sub Volume (master)
OP(0, 0x062, 0x0c0, 0x408, 0x400);
OP(0, 0x063, 0x0c0, 0x409, 0x400);
/* input buffer */ ROUTING_PATCH_START(rpatch, "Routing");
OP(6, 0x102, AC97_IN_L, 0x40, 0x40); ROUTING_PATCH_END(rpatch);
OP(6, 0x103, AC97_IN_R, 0x40, 0x40);
/* delimiter patch */
patch = PATCH(mgr, patch_n);
patch->code_size = 0;
/* Digital In + PCM + MULTI_FRONT-> AC97 out (front speakers)*/
OP(6, AC97_FRONT_L, 0x100, 0x10c, 0x113); sblive_writeptr(card, 0x53, 0, 0);
} else {
CONNECT(MULTI_FRONT_L, AC97_FRONT_L); for (i = 0; i < 512 ; i++)
CONNECT(PCM_IN_L, AC97_FRONT_L); OP(6, 0x40, 0x40, 0x40, 0x40);
CONNECT(SPDIF_CD_L, AC97_FRONT_L);
OP(6, AC97_FRONT_R, 0x101, 0x10e, 0x114);
CONNECT(MULTI_FRONT_R, AC97_FRONT_R); for (i = 0; i < 256; i++)
CONNECT(PCM_IN_R, AC97_FRONT_R); sblive_writeptr_tag(card, 0,
CONNECT(SPDIF_CD_R, AC97_FRONT_R); FXGPREGBASE + i, 0,
TANKMEMADDRREGBASE + i, 0,
TAGLIST_END);
/* Digital In + PCM + AC97 In + PCM1 + MULTI_REAR --> Rear Channel */
OP(6, 0x104, PCM1_IN_L, 0x100, 0x115); pc = 0;
OP(6, 0x104, 0x104, 0x10c, 0x102);
CONNECT(MULTI_REAR_L, ANALOG_REAR_L); //first free GPR = 0x11b
CONNECT(AC97_IN_L, ANALOG_REAR_L);
CONNECT(PCM_IN_L, ANALOG_REAR_L);
CONNECT(SPDIF_CD_L, ANALOG_REAR_L); /* FX volume correction and Volume control*/
CONNECT(PCM1_IN_L, ANALOG_REAR_L); 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(6, 0x105, PCM1_IN_R, 0x101, 0x116); OP(4, 0x112, 0x40, PCM_IN_L, 0x44); //*4
OP(6, 0x105, 0x105, 0x10e, 0x103); OP(0, 0x100, 0x040, 0x112, 0x106); //*vol
INPUT_PATCH_END(patch);
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 */ INPUT_PATCH_START(patch, "Pcm R vol", 0x1, 0);
OP(6, 0x10a, 0x100, 0x102, 0x10c); GET_OUTPUT_GPR(patch, 0x101, 0x1);
OP(6, 0x10a, 0x10a, 0x113, 0x40); GET_CONTROL_GPR(patch, 0x107, "Vol", 0, 0x7fffffff);
GET_DYNAMIC_GPR(patch, 0x112);
CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L); OP(4, 0x112, 0x40, PCM_IN_R, 0x44);
CONNECT(PCM_IN_L, DIGITAL_OUT_L); OP(0, 0x101, 0x040, 0x112, 0x107);
CONNECT(AC97_IN_L, DIGITAL_OUT_L);
CONNECT(SPDIF_CD_L, DIGITAL_OUT_L);
OP(6, 0x10b, 0x101, 0x103, 0x10e); INPUT_PATCH_END(patch);
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 */ // CD-Digital In Volume control
OP(6, ADC_REC_L, 0x102, 0x40, 0x40); INPUT_PATCH_START(patch, "CD-Digital Vol L", 0x12, 0);
GET_OUTPUT_GPR(patch, 0x10c, 0x12);
GET_CONTROL_GPR(patch, 0x10d, "Vol", 0, 0x7fffffff);
CONNECT(AC97_IN_L, ADC_REC_L); OP(0, 0x10c, 0x040, SPDIF_CD_L, 0x10d);
INPUT_PATCH_END(patch);
OP(6, ADC_REC_R, 0x103, 0x40, 0x40); INPUT_PATCH_START(patch, "CD-Digital Vol R", 0x13, 0);
GET_OUTPUT_GPR(patch, 0x10e, 0x13);
GET_CONTROL_GPR(patch, 0x10f, "Vol", 0, 0x7fffffff);
CONNECT(AC97_IN_R, ADC_REC_R); 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;
/* fx12:Analog-Center */ GET_OUTPUT_GPR(patch, 0x113, MULTI_FRONT_L);
OP(6, ANALOG_CENTER, 0x117, 0x40, 0x40); GET_OUTPUT_GPR(patch, 0x114, MULTI_FRONT_R);
CONNECT(MULTI_CENTER, ANALOG_CENTER); 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);
/* fx11:Analog-LFE */ OP(4, 0x113, 0x40, MULTI_FRONT_L, 0x44);
OP(6, ANALOG_LFE, 0x118, 0x40, 0x40); OP(4, 0x114, 0x40, MULTI_FRONT_R, 0x44);
CONNECT(MULTI_LFE, ANALOG_LFE); 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 */ //Routing patch start
OP(6, DIGITAL_LFE, 0x118, 0x40, 0x40); ROUTING_PATCH_START(rpatch, "Routing");
CONNECT(MULTI_LFE, DIGITAL_LFE); 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 // Rear volume control
OUTPUT_PATCH_START(patch, "Vol Rear L", 0x8, 0); OUTPUT_PATCH_START(patch, "Vol Rear L", 0x8, 0);
GET_INPUT_GPR(patch, 0x104, 0x8); GET_INPUT_GPR(patch, 0x104, 0x8);
GET_CONTROL_GPR(patch, 0x119, "Vol", 0, 0x7fffffff); GET_CONTROL_GPR(patch, 0x119, "Vol", 0, 0x7fffffff);
OP(0, ANALOG_REAR_L, 0x040, 0x104, 0x119); OP(0, ANALOG_REAR_L, 0x040, 0x104, 0x119);
OUTPUT_PATCH_END(patch); 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); OP(0, ANALOG_REAR_R, 0x040, 0x105, 0x11a);
GET_INPUT_GPR(patch, 0x105, 0x9); OUTPUT_PATCH_END(patch);
GET_CONTROL_GPR(patch, 0x11a, "Vol", 0, 0x7fffffff);
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 OP(0, DIGITAL_OUT_L, 0x040, 0x10a, 0x108);
OUTPUT_PATCH_START(patch, "Vol Master L", 0x2, 1); OUTPUT_PATCH_END(patch);
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);
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); OP(0, DIGITAL_OUT_R, 0x040, 0x10b, 0x109);
GET_INPUT_GPR(patch, 0x10b, 0x3); OUTPUT_PATCH_END(patch);
GET_CONTROL_GPR(patch, 0x109, "Vol", 0, 0x7fffffff);
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); sblive_writeptr(card, DBG, 0, 0);
patch->code_size = 0; }
sblive_writeptr(card, DBG, 0, 0);
mgr->lock = SPIN_LOCK_UNLOCKED; mgr->lock = SPIN_LOCK_UNLOCKED;
// Set up Volume controls, try to keep this the same for both Audigy and Live
//Master volume //Master volume
mgr->ctrl_gpr[SOUND_MIXER_VOLUME][0] = 8; mgr->ctrl_gpr[SOUND_MIXER_VOLUME][0] = 8;
...@@ -749,8 +921,16 @@ static int __devinit fx_init(struct emu10k1_card *card) ...@@ -749,8 +921,16 @@ static int __devinit fx_init(struct emu10k1_card *card)
emu10k1_set_volume_gpr(card, 0xd, left, VOL_5BIT); emu10k1_set_volume_gpr(card, 0xd, left, VOL_5BIT);
emu10k1_set_volume_gpr(card, 0xf, right, 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_supported_mixers &= ~SOUND_MASK_PCM;
card->ac97_stereo_mixers &= ~SOUND_MASK_PCM; card->ac97_stereo_mixers &= ~SOUND_MASK_PCM;
...@@ -789,6 +969,13 @@ static int __devinit hw_init(struct emu10k1_card *card) ...@@ -789,6 +969,13 @@ static int __devinit hw_init(struct emu10k1_card *card)
SOLEH, 0, SOLEH, 0,
TAGLIST_END); TAGLIST_END);
if (card->is_audigy) {
sblive_writeptr_tag(card,0,
0x5e,0xf00,
0x5f,0x3,
TAGLIST_END);
}
/* Init envelope engine */ /* Init envelope engine */
for (nCh = 0; nCh < NUM_G; nCh++) { for (nCh = 0; nCh < NUM_G; nCh++) {
sblive_writeptr_tag(card, nCh, sblive_writeptr_tag(card, nCh,
...@@ -824,6 +1011,21 @@ static int __devinit hw_init(struct emu10k1_card *card) ...@@ -824,6 +1011,21 @@ static int __devinit hw_init(struct emu10k1_card *card)
ENVVAL, 0, ENVVAL, 0,
TAGLIST_END); TAGLIST_END);
sblive_writeptr(card, CPF, nCh, 0); 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 @@ static int __devinit hw_init(struct emu10k1_card *card) ...@@ -858,6 +1060,25 @@ static int __devinit hw_init(struct emu10k1_card *card)
TAGLIST_END); 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 */ ret = fx_init(card); /* initialize effects engine */
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -905,16 +1126,30 @@ static int __devinit hw_init(struct emu10k1_card *card) ...@@ -905,16 +1126,30 @@ static int __devinit hw_init(struct emu10k1_card *card)
/* Lock Tank Memory = 1 */ /* Lock Tank Memory = 1 */
/* Lock Sound Memory = 0 */ /* Lock Sound Memory = 0 */
/* Auto Mute = 1 */ /* Auto Mute = 1 */
if (card->is_audigy) {
if (card->model == 0x20 || card->model == 0xc400 || if (card->chiprev == 4)
(card->model == 0x21 && card->chiprev < 6)) emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | HCFG_AC3ENABLE_GPSPDIF | HCFG_AUTOMUTE | HCFG_JOYENABLE);
emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE); else
else emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | 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 */ /* Enable Vol_Ctrl irqs */
emu10k1_irq_enable(card, INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_FXDSPENABLE); 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 */ /* FIXME: TOSLink detection */
card->has_toslink = 0; card->has_toslink = 0;
...@@ -967,7 +1202,7 @@ static int __devinit emu10k1_init(struct emu10k1_card *card) ...@@ -967,7 +1202,7 @@ static int __devinit emu10k1_init(struct emu10k1_card *card)
return 0; return 0;
} }
static void __devinit emu10k1_cleanup(struct emu10k1_card *card) static void emu10k1_cleanup(struct emu10k1_card *card)
{ {
int ch; int ch;
...@@ -1012,6 +1247,8 @@ static void __devinit emu10k1_cleanup(struct emu10k1_card *card) ...@@ -1012,6 +1247,8 @@ static void __devinit emu10k1_cleanup(struct emu10k1_card *card)
SOLEH, 0, SOLEH, 0,
TAGLIST_END); 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->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); pci_free_consistent(card->pci_dev, card->silentpage.size, card->silentpage.addr, card->silentpage.dma_handle);
...@@ -1074,6 +1311,9 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev ...@@ -1074,6 +1311,9 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase, card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase,
card->iobase + card->length - 1, card->irq); 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); pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
card->is_aps = (subsysvid == EMU_APS_SUBID); card->is_aps = (subsysvid == EMU_APS_SUBID);
...@@ -1083,13 +1323,13 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev ...@@ -1083,13 +1323,13 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
init_waitqueue_head(&card->open_wait); init_waitqueue_head(&card->open_wait);
ret = emu10k1_audio_init(card); ret = emu10k1_audio_init(card);
if(ret < 0) { if (ret < 0) {
printk(KERN_ERR "emu10k1: cannot initialize audio devices\n"); printk(KERN_ERR "emu10k1: cannot initialize audio devices\n");
goto err_audio; goto err_audio;
} }
ret = emu10k1_mixer_init(card); ret = emu10k1_mixer_init(card);
if(ret < 0) { if (ret < 0) {
printk(KERN_ERR "emu10k1: cannot initialize AC97 codec\n"); printk(KERN_ERR "emu10k1: cannot initialize AC97 codec\n");
goto err_mixer; goto err_mixer;
} }
...@@ -1109,10 +1349,28 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev ...@@ -1109,10 +1349,28 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
if (card->is_aps) if (card->is_aps)
emu10k1_ecard_init(card); 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); list_add(&card->list, &emu10k1_devs);
return 0; return 0;
err_proc:
emu10k1_unregister_devices(card);
err_register:
emu10k1_cleanup(card);
err_emu10k1_init: err_emu10k1_init:
emu10k1_midi_cleanup(card); emu10k1_midi_cleanup(card);
...@@ -1141,9 +1399,11 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev) ...@@ -1141,9 +1399,11 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
list_del(&card->list); list_del(&card->list);
emu10k1_unregister_devices(card);
emu10k1_cleanup(card); emu10k1_cleanup(card);
emu10k1_midi_cleanup(card); emu10k1_midi_cleanup(card);
emu10k1_mixer_cleanup(card); emu10k1_mixer_cleanup(card);
emu10k1_proc_cleanup(card);
emu10k1_audio_cleanup(card); emu10k1_audio_cleanup(card);
free_irq(card->irq, card); free_irq(card->irq, card);
release_region(card->iobase, card->length); release_region(card->iobase, card->length);
......
...@@ -52,4 +52,27 @@ struct emu10k1_mididevice ...@@ -52,4 +52,27 @@ struct emu10k1_mididevice
struct list_head mid_hdrs; 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 */ #endif /* _MIDI_H */
...@@ -136,7 +136,7 @@ static void set_bass(struct emu10k1_card *card, int l, int r) ...@@ -136,7 +136,7 @@ static void set_bass(struct emu10k1_card *card, int l, int r)
r = (r * 40 + 50) / 100; r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++) 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) static void set_treble(struct emu10k1_card *card, int l, int r)
...@@ -147,7 +147,7 @@ static void set_treble(struct emu10k1_card *card, int l, int r) ...@@ -147,7 +147,7 @@ static void set_treble(struct emu10k1_card *card, int l, int r)
r = (r * 40 + 50) / 100; r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++) 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]= { const char volume_params[SOUND_MIXER_NRDEVICES]= {
...@@ -206,22 +206,25 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -206,22 +206,25 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
switch (ctl->cmd) { switch (ctl->cmd) {
#ifdef DBGEMU #ifdef DBGEMU
case CMD_WRITEFN0: 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; break;
#endif
case CMD_WRITEPTR: 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; ret = -EINVAL;
break; break;
} }
if ((ctl->val[0] & 0x7ff) > 0x3f)
ctl->val[1] = 0x00;
sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]); sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]);
break; break;
#endif
case CMD_READFN0: case CMD_READFN0:
ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]); ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]);
...@@ -286,16 +289,13 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -286,16 +289,13 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
case CMD_GETVOICEPARAM: case CMD_GETVOICEPARAM:
ctl->val[0] = card->waveout.send_routing[0]; ctl->val[0] = card->waveout.send_routing[0];
ctl->val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 | ctl->val[1] = card->waveout.send_dcba[0];
card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24;
ctl->val[2] = card->waveout.send_routing[1]; ctl->val[2] = card->waveout.send_routing[1];
ctl->val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 | ctl->val[3] = card->waveout.send_dcba[1];
card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24;
ctl->val[4] = card->waveout.send_routing[2]; ctl->val[4] = card->waveout.send_routing[2];
ctl->val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 | ctl->val[5] = card->waveout.send_dcba[2];
card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24;
if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl))) if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT; ret = -EFAULT;
...@@ -303,23 +303,14 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -303,23 +303,14 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break; break;
case CMD_SETVOICEPARAM: case CMD_SETVOICEPARAM:
card->waveout.send_routing[0] = ctl->val[0] & 0xffff; card->waveout.send_routing[0] = ctl->val[0];
card->waveout.send_a[0] = ctl->val[1] & 0xff; card->waveout.send_dcba[0] = ctl->val[1];
card->waveout.send_b[0] = (ctl->val[1] >> 8) & 0xff;
card->waveout.send_c[0] = (ctl->val[1] >> 16) & 0xff; card->waveout.send_routing[1] = ctl->val[2];
card->waveout.send_d[0] = (ctl->val[1] >> 24) & 0xff; card->waveout.send_dcba[1] = ctl->val[3];
card->waveout.send_routing[1] = ctl->val[2] & 0xffff; card->waveout.send_routing[2] = ctl->val[4];
card->waveout.send_a[1] = ctl->val[3] & 0xff; card->waveout.send_dcba[2] = ctl->val[5];
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;
break; break;
...@@ -416,12 +407,16 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -416,12 +407,16 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break; break;
case CMD_SETGPOUT: 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; ret= -EINVAL;
break; 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; break;
case CMD_GETGPR2OSS: case CMD_GETGPR2OSS:
...@@ -493,13 +488,20 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -493,13 +488,20 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break; break;
case CMD_PRIVATE3_VERSION: 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))) if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT; ret = -EFAULT;
break; break;
case CMD_AC97_BOOST: case CMD_AC97_BOOST:
if(ctl->val[0]) if (ctl->val[0])
emu10k1_ac97_write(card->ac97, 0x18, 0x0); emu10k1_ac97_write(card->ac97, 0x18, 0x0);
else else
emu10k1_ac97_write(card->ac97, 0x18, 0x0808); emu10k1_ac97_write(card->ac97, 0x18, 0x0808);
...@@ -556,7 +558,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -556,7 +558,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
card->tankmem.size = size; 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); emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
} }
...@@ -623,8 +625,13 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -623,8 +625,13 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned
if (cmd == SOUND_MIXER_INFO) { if (cmd == SOUND_MIXER_INFO) {
mixer_info info; mixer_info info;
strncpy(info.id, card->ac97->name, sizeof(info.id)); strlcpy(info.id, card->ac97->name, sizeof(info.id));
strncpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
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; info.modify_counter = card->ac97->modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info))) if (copy_to_user((void *)arg, &info, sizeof(info)))
......
...@@ -109,7 +109,7 @@ static int pt_putblock(struct emu10k1_wavedevice *wave_dev, u16 *block, int nonb ...@@ -109,7 +109,7 @@ static int pt_putblock(struct emu10k1_wavedevice *wave_dev, u16 *block, int nonb
return 0; return 0;
} }
static int pt_setup(struct emu10k1_wavedevice *wave_dev) int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev)
{ {
u32 bits; u32 bits;
struct emu10k1_card *card = wave_dev->card; struct emu10k1_card *card = wave_dev->card;
...@@ -155,7 +155,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count) ...@@ -155,7 +155,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count)
pt->prepend_size = 0; pt->prepend_size = 0;
if (pt->buf == NULL) if (pt->buf == NULL)
return -ENOMEM; return -ENOMEM;
pt_setup(wave_dev); emu10k1_pt_setup(wave_dev);
} }
if (pt->prepend_size) { if (pt->prepend_size) {
int needed = PT_BLOCKSIZE - pt->prepend_size; int needed = PT_BLOCKSIZE - pt->prepend_size;
...@@ -208,13 +208,14 @@ void emu10k1_pt_stop(struct emu10k1_card *card) ...@@ -208,13 +208,14 @@ void emu10k1_pt_stop(struct emu10k1_card *card)
if (pt->state != PT_STATE_INACTIVE) { if (pt->state != PT_STATE_INACTIVE) {
DPF(2, "digital pass-through stopped\n"); 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++) { for (i = 0; i < 3; i++) {
if (pt->spcs_to_use & (1 << i)) if (pt->spcs_to_use & (1 << i))
sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]); sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
} }
pt->state = PT_STATE_INACTIVE; pt->state = PT_STATE_INACTIVE;
kfree(pt->buf); if(pt->buf)
kfree(pt->buf);
} }
} }
......
...@@ -63,7 +63,36 @@ struct pt_data ...@@ -63,7 +63,36 @@ struct pt_data
spinlock_t lock; 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); 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_stop(struct emu10k1_card *card);
void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev); void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev);
......
...@@ -74,7 +74,7 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst) ...@@ -74,7 +74,7 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
DPF(2, "recording source: AC97\n"); DPF(2, "recording source: AC97\n");
buffer->sizereg = ADCBS; buffer->sizereg = ADCBS;
buffer->addrreg = ADCBA; buffer->addrreg = ADCBA;
buffer->idxreg = ADCIDX_IDX; buffer->idxreg = card->is_audigy ? A_ADCIDX_IDX : ADCIDX_IDX;
switch (wiinst->format.samplingrate) { switch (wiinst->format.samplingrate) {
case 0xBB80: case 0xBB80:
...@@ -95,21 +95,27 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst) ...@@ -95,21 +95,27 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
case 0x3E80: case 0x3E80:
buffer->adcctl = ADCCR_SAMPLERATE_16; buffer->adcctl = ADCCR_SAMPLERATE_16;
break; break;
// FIXME: audigy supports 12kHz recording
/*
case ????:
buffer->adcctl = A_ADCCR_SAMPLERATE_12;
break;
*/
case 0x2B11: case 0x2B11:
buffer->adcctl = ADCCR_SAMPLERATE_11; buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_11 : ADCCR_SAMPLERATE_11;
break; break;
case 0x1F40: case 0x1F40:
buffer->adcctl = ADCCR_SAMPLERATE_8; buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_8 : ADCCR_SAMPLERATE_8;
break; break;
default: default:
BUG(); BUG();
break; break;
} }
buffer->adcctl |= ADCCR_LCHANENABLE; buffer->adcctl |= card->is_audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
if (wiinst->format.channels == 2) if (wiinst->format.channels == 2)
buffer->adcctl |= ADCCR_RCHANENABLE; buffer->adcctl |= card->is_audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
break; break;
......
...@@ -32,6 +32,34 @@ ...@@ -32,6 +32,34 @@
#include "voicemgr.h" #include "voicemgr.h"
#include "8010.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_target<PITCH_48000)
return CCCA_INTERPROM_1;
else if(voice->pitch_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 - * emu10k1_voice_alloc_buffer -
* *
...@@ -216,17 +244,25 @@ void emu10k1_voice_playback_setup(struct emu_voice *voice) ...@@ -216,17 +244,25 @@ void emu10k1_voice_playback_setup(struct emu_voice *voice)
voice->start += start; voice->start += start;
for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { 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 */ /* Stop CA */
/* Assumption that PT is already 0 so no harm overwriting */ /* 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, sblive_writeptr_tag(card, voice->num + i,
/* CSL, ST, CA */ /* CSL, ST, CA */
DSL, voice->endloop | (voice->params[i].send_d << 24), DSL, voice->endloop | (voice->params[i].send_dcba & 0xff000000),
PSST, voice->startloop | (voice->params[i].send_c << 24), PSST, voice->startloop | ((voice->params[i].send_dcba & 0x00ff0000) << 8),
CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT), CCCA, (voice->start) | emu10k1_select_interprom(card,voice) |
((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
/* Clear filter delay memory */ /* Clear filter delay memory */
Z1, 0, Z1, 0,
Z2, 0, Z2, 0,
......
...@@ -48,11 +48,13 @@ struct voice_param ...@@ -48,11 +48,13 @@ struct voice_param
/* FX bus amount send */ /* FX bus amount send */
u32 send_routing; 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 initial_fc;
u32 fc_target; u32 fc_target;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment