patch-2.3.36 linux/drivers/sound/trident.c
Next file: linux/drivers/sound/trident.h
Previous file: linux/drivers/sound/msnd_pinnacle.c
Back to the patch index
Back to the overall index
- Lines: 3743
- Date:
Wed Dec 29 17:29:43 1999
- Orig file:
v2.3.35/linux/drivers/sound/trident.c
- Orig date:
Tue Dec 7 09:32:46 1999
diff -u --recursive --new-file v2.3.35/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
@@ -1,36 +1,41 @@
-/*****************************************************************************
+/*
*
- * Trident 4D-Wave OSS driver for Linux 2.2.x
+ * Trident 4D-Wave/SiS 7018 OSS driver for Linux 2.2.x
*
* Driver: Alan Cox <alan@redhat.com>
*
* Built from:
- * Low level code: <audio@tridentmicro.com> from ALSA
- * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- * Extended by: Zach Brown <zab@redhat.com>
+ * Low level code: <audio@tridentmicro.com> from ALSA
+ * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Extended by: Zach Brown <zab@redhat.com>
*
- * Hacked up by:
- * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ * Hacked up by:
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ * Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
*
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ * History
+ * v0.03 Dec 24 1999 Ollie Lho
+ * mem leak in prog_dmabuf and dealloc_dmabuf removed
+ * v0.02 Dec 15 1999 Ollie Lho
+ * SiS 7018 support added, playback O.K.
+ * v0.01 Alan Cox et. al.
+ * Initial Release in kernel 2.3.30, does not work
*/
-
-/*****************************************************************************/
-
#include <linux/config.h>
#include <linux/module.h>
@@ -61,17 +66,10 @@
/* --------------------------------------------------------------------- */
-#define M_DEBUG 1
-
-#ifdef M_DEBUG
-static int debug=0;
-#define M_printk(args...) {if (debug) printk(args);}
-#else
-#define M_printk(x)
-#endif
+#undef DEBUG
/* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.01"
+#define DRIVER_VERSION "0.03"
#define TRIDENT_FMT_STEREO 0x01
#define TRIDENT_FMT_16BIT 0x02
@@ -79,33 +77,53 @@
#define TRIDENT_DAC_SHIFT 0
#define TRIDENT_ADC_SHIFT 4
-#define TRIDENT_ENABLE_PE 1
-#define TRIDENT_ENABLE_RE 2
+#define TRIDENT_ENABLE_PE 1
+#define TRIDENT_ENABLE_RE 2
+#define DAC_RUNNING 1
+#define ADC_RUNNING 2
-#define TRIDENT_CARD_MAGIC 0x5072696E
-#define TRIDENT_STATE_MAGIC 0x63657373
+#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
+#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
#define NR_DSPS 8
-#define SND_DEV_DSP16 5
+#define SND_DEV_DSP16 5
static const unsigned sample_size[] = { 1, 2, 2, 4 };
static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
-enum card_types_t {
- TYPE_4DWAVE_DX,
- TYPE_4DWAVE_NX
+struct pci_audio_info {
+ u16 vendor;
+ u16 device;
+ char *name;
};
-static const char *card_names[]={
- [TYPE_4DWAVE_DX] = "Trident 4DWave DX",
- [TYPE_4DWAVE_NX] = "Trident 4DWave NX",
+static struct pci_audio_info pci_audio_devices[] = {
+ {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, "Trident 4DWave DX"},
+ {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, "Trident 4DWave NX"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"}
};
+static struct {
+ unsigned int id;
+ char *name;
+} snd_ac97_codec_ids[] = {
+ {0x414B4D00, "Asahi Kasei AK4540" },
+ {0x41445340, "Analog Devices AD1881" },
+ {0x43525900, "Cirrus Logic CS4297" },
+ {0x43525913, "Cirrus Logic CS4297A" },
+ {0x43525931, "Cirrus Logic CS4299" },
+ {0x4e534331, "National Semiconductor LM4549"},
+ {0x83847600, "SigmaTel STAC????" },
+ {0x83847604, "SigmaTel STAC9701/3/4/5"},
+ {0x83847605, "SigmaTel STAC9704" },
+ {0x83847608, "SigmaTel STAC9708" },
+ {0x83847609, "SigmaTel STAC9721/23" },
+ {0x00000000, NULL}
+};
typedef struct tChannelControl
{
@@ -149,7 +167,7 @@
unsigned fragshift;
int chan[2]; /* Hardware channel */
/* XXX zab - swptr only in here so that it can be referenced by
- clear_advance, as far as I can tell :( */
+ clear_advance, as far as I can tell :( */
unsigned hwptr, swptr;
unsigned total_bytes;
int count;
@@ -172,7 +190,31 @@
u8 bDMAStart;
};
-
+
+struct trident_pcm_bank {
+ /* registers to control bank operations */
+ u32 start;
+ u32 stop;
+ u32 aint;
+ u32 aint_en;
+ /* each bank has 32 channels */
+ u32 bitmap; /* channel allocation bitmap */
+ //struct trident_channel channels[32];
+};
+
+struct trident_mixer {
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ /* the caller must guarantee arg sanity before calling these */
+ /* int (*read_mixer)(struct trident_card *card, int index);*/
+ void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,
+ unsigned int right);
+ int (*recmask_io)(struct trident_card *card,int rw,int mask);
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
struct trident_card {
unsigned int magic;
@@ -180,23 +222,23 @@
struct trident_card *next;
/* The trident has a certain amount of cross channel interaction
- so we use a single per card lock */
-
+ so we use a single per card lock */
spinlock_t lock;
- int dev_mixer;
-
- int card_type;
+ struct pci_audio_info *pci_info;
+ struct pci_dev * pci_dev;
+ u16 pci_id;
/* as most of this is static,
- perhaps it should be a pointer to a global struct */
+ perhaps it should be a pointer to a global struct */
+ int dev_mixer;
struct mixer_goo {
int modcnt;
int supported_mixers;
int stereo_mixers;
int record_sources;
/* the caller must guarantee arg sanity before calling these */
-/* int (*read_mixer)(struct trident_card *card, int index);*/
+ /* int (*read_mixer)(struct trident_card *card, int index);*/
void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,unsigned int right);
int (*recmask_io)(struct trident_card *card,int rw,int mask);
unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
@@ -208,41 +250,12 @@
unsigned long iobase;
u32 irq;
- u32 ChanMap[2];
- int ChanPCMcnt;
- int ChanPCM;
+ u32 bitmap[2];
CHANNELCONTROL ChRegs;
int ChanDwordCount;
};
-static struct timer_list debug_timer;
-
-#define IWriteAinten( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define IReadAinten( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define ReadAint( x ) \
- IReadAint( x )
-
-#define WriteAint( x ) \
- IWriteAint( x )
-
-#define IWriteAint( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));}
-
-#define IReadAint( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));}
-
+static struct trident_card *devs = NULL;
/*
* Trident support library routines
@@ -252,12 +265,12 @@
void ResetAinten( struct trident_state *trident, int ChannelNum)
Description: This routine will disable interrupts and ack any
- existing interrupts for specified channel.
+ existing interrupts for specified channel.
- Parameters: trident - pointer to target device class for 4DWave.
- ChannelNum - channel number
+ Parameters: trident - pointer to target device class for 4DWave.
+ ChannelNum - channel number
- returns: TRUE if everything went ok, else FALSE.
+ returns: TRUE if everything went ok, else FALSE.
---------------------------------------------------------------------------*/
@@ -279,105 +292,171 @@
void EnableEndInterrupts( struct trident_card *trident)
Description: This routine will enable end of loop interrupts.
- End of loop interrupts will occur when a running
- channel reaches ESO.
+ End of loop interrupts will occur when a running
+ channel reaches ESO.
- Parameters: trident - pointer to target device class for 4DWave.
+ Parameters: trident - pointer to target device class for 4DWave.
- returns: TRUE if everything went ok, else FALSE.
+ returns: TRUE if everything went ok, else FALSE.
---------------------------------------------------------------------------*/
-static int EnableEndInterrupts(struct trident_card * trident)
+static int trident_enable_end_interrupts(struct trident_card * trident)
{
- unsigned int GlobalControl;
+ u32 GlobalControl;
- GlobalControl = inb(TRID_REG(trident, T4D_LFO_GC_CIR + 1));
- GlobalControl |= 0x10;
- outb(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR + 1));
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
- M_printk("(trident) globctl=%02X\n", GlobalControl);
- M_printk("(trident) enabled end interrupts\n");
+ switch (trident->pci_id)
+ {
+ case PCI_DEVICE_ID_SI_7018:
+ GlobalControl |= (ENDLP_IE | BANK_B_EN);
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ GlobalControl |= ENDLP_IE;
+ break;
+ default:
+ return FALSE;
+ }
+
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+ printk("trident: Enable End Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
return (TRUE);
}
+static int trident_enable_middle_interrupts(struct trident_card * trident)
+{
+ u32 GlobalControl;
+
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+
+ switch (trident->pci_id)
+ {
+ case PCI_DEVICE_ID_SI_7018:
+ GlobalControl |= (MIDLP_IE | BANK_B_EN);
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ default:
+ GlobalControl |= MIDLP_IE;
+ break;
+ }
+
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+ printk("trident: Enable Middle Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
+ return (TRUE);
+}
/*---------------------------------------------------------------------------
-e void DisableEndInterrupts( struct trident_card *trident)
+ void DisableEndInterrupts( struct trident_card *trident)
Description: This routine will disable end of loop interrupts.
- End of loop interrupts will occur when a running
- channel reaches ESO.
+ End of loop interrupts will occur when a running
+ channel reaches ESO.
- Parameters:
- trident - pointer to target device class for 4DWave.
+ Parameters:
+ trident - pointer to target device class for 4DWave.
- returns: TRUE if everything went ok, else FALSE.
+ returns: TRUE if everything went ok, else FALSE.
---------------------------------------------------------------------------*/
-static int DisableEndInterrupts(struct trident_card * trident)
+static int trident_disable_end_interrupts(struct trident_card * trident)
{
- unsigned int GlobalControl;
+ u32 GlobalControl;
- GlobalControl = inb(TRID_REG(trident, T4D_LFO_GC_CIR + 1));
- GlobalControl &= ~0x10;
- outb(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR + 1));
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+ GlobalControl &= ~ENDLP_IE;
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
- M_printk("(trident) disabled end interrupts\n");
- M_printk("(trident) globctl=%02X\n", GlobalControl);
+#ifdef DEBUG
+ printk("trident: Disabled End Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
return (TRUE);
}
+static int trident_disable_middle_interrupts(struct trident_card * trident)
+{
+ u32 GlobalControl;
+
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+ GlobalControl &= ~MIDLP_IE;
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+ printk("trident: Disabled Middle Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
+ return (TRUE);
+}
/*---------------------------------------------------------------------------
void trident_enable_voice_irq( unsigned int HwChannel )
Description: Enable an interrupt channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_enable_voice_irq(struct trident_card * trident, unsigned int HwChannel)
+void trident_enable_voice_irq(struct trident_card * trident, unsigned int channel)
{
- unsigned int x, Data, ChanDwordCount;
+ unsigned int bank, mask, ChanDwordCount;
+ u32 reg;
+
+ bank = channel >> 5;
+ mask = 1 << (channel & 0x1f);
- x = HwChannel >> 5;
- Data = 1 << (HwChannel & 0x1f);
ChanDwordCount = trident->ChanDwordCount;
+
IReadAinten(&trident->ChRegs);
- trident->ChRegs.lpChAinten[x] |= Data;
+ trident->ChRegs.lpChAinten[bank] |= mask;
IWriteAinten(&trident->ChRegs);
- M_printk("(trident) enabled voice IRQ %d\n", HwChannel);
+
+#ifdef DEBUG
+ reg = inl(TRID_REG(trident, T4D_AINTEN_B));
+ printk("trident: enabled IRQ on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
void trident_disable_voice_irq( unsigned int HwChannel )
Description: Disable an interrupt channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_disable_voice_irq(struct trident_card * trident, unsigned int HwChannel)
+void trident_disable_voice_irq(struct trident_card * trident, unsigned int channel)
{
- unsigned int x, Data, ChanDwordCount;
+ unsigned int bank, mask, ChanDwordCount;
+ u32 reg;
+
+ bank = channel >> 5;
+ mask = 1 << (channel & 0x1f);
- x = HwChannel >> 5;
- Data = 1 << (HwChannel & 0x1f);
ChanDwordCount = trident->ChanDwordCount;
IReadAinten(&trident->ChRegs);
- trident->ChRegs.lpChAinten[x] &= ~Data;
+ trident->ChRegs.lpChAinten[bank] &= ~mask;
IWriteAinten(&trident->ChRegs);
- M_printk("(trident) disabled voice IRQ %d\n", HwChannel);
+
+#ifdef DEBUG
+ reg = inl(TRID_REG(trident, T4D_AINTEN_B));
+ printk("trident: disabled IRQ on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
@@ -391,29 +470,38 @@
---------------------------------------------------------------------------*/
-static int AllocateChannelPCM(struct trident_card *trident)
+static int trident_alloc_pcm_channel(struct trident_card *trident)
{
int idx;
- if (trident->ChanPCMcnt >= trident->ChanPCM)
- {
- M_printk(KERN_DEBUG "(trident) no channels available.\n");
+ if (trident->bitmap[BANK_B] == ~0UL) {
+ /* not more free channels avaliable */
+ printk(KERN_ERR "trident: no more channels available on Bank B.\n");
return -1;
}
for (idx = 31; idx >= 0; idx--) {
- if (!(trident->ChanMap[1] & (1 << idx))) {
- trident->ChanMap[1] |= 1 << idx;
- trident->ChanPCMcnt++;
+ if (!(trident->bitmap[BANK_B] & (1 << idx))) {
+ trident->bitmap[BANK_B] |= 1 << idx;
return idx + 32;
}
}
+
+#ifdef ABUSE_BANK_A
+ /* channels in Bank A should be reserved for synthesizer
+ not for normal use (channels in Bank A can't record) */
+ if (trident->bitmap[BANK_A] == ~0UL) {
+ /* not more free channels avaliable */
+ printk(KERN_ERR "trident: no channels available on Bank A.\n");
+ return -1;
+ }
for (idx = 31; idx >= 0; idx--) {
- if (!(trident->ChanMap[0] & (1 << idx))) {
- trident->ChanMap[0] |= 1 << idx;
- trident->ChanPCMcnt++;
+ if (!(trident->bitmap[BANK_A] & (1 << idx))) {
+ trident->bitmap[BANK_A] |= 1 << idx;
return idx;
}
}
+#endif
+
return -1;
}
@@ -423,19 +511,29 @@
Description: Free hardware channel.
Parameters : trident - pointer to target device class for 4DWave.
- channel - hardware channel number 0-63
+ channel - hardware channel number 0-63
Return Value: none
---------------------------------------------------------------------------*/
-static void FreeChannelPCM(struct trident_card *trident, int channel)
+static void trident_free_pcm_channel(struct trident_card *trident, int channel)
{
+ int bank;
+
+#ifdef ABUSE_BANK_A
if (channel < 0 || channel > 63)
return;
- if (trident->ChanMap[channel>>5] & (1 << (channel & 0x1f))) {
- trident->ChanMap[channel>>5] &= ~(1 << (channel & 0x1f));
- trident->ChanPCMcnt--;
+#else
+ if (channel < 31 || channel > 63)
+ return;
+#endif
+
+ bank = channel >> 5;
+ channel = channel & 0x1f;
+
+ if (trident->bitmap[bank] & (1 << (channel))) {
+ trident->bitmap[bank] &= ~(1 << (channel));
}
}
@@ -443,113 +541,127 @@
void trident_start_voice( ULONG HwChannel )
Description: Start a channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_start_voice(struct trident_card * trident, unsigned int HwChannel)
+void trident_start_voice(struct trident_card * trident, unsigned int channel)
{
- unsigned int x = HwChannel >> 5;
- unsigned int Data = 1 << (HwChannel & 0x1f);
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
- outl(Data, TRID_REG(trident, trident->ChRegs.lpAChStart[x]));
- M_printk("(trident) start voice %d\n", HwChannel);
+ outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStart[bank]));
+#ifdef DEBUG
+ printk("trident: start voice on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
void trident_stop_voice( ULONG HwChannel )
Description: Stop a channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_stop_voice(struct trident_card * trident, unsigned int HwChannel)
+void trident_stop_voice(struct trident_card * trident, unsigned int channel)
{
- unsigned int x = HwChannel >> 5;
- unsigned int Data = 1 << (HwChannel & 0x1f);
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
- outl(Data, TRID_REG(trident, trident->ChRegs.lpAChStop[x]));
- M_printk("(trident) stop voice %d\n", HwChannel);
+ outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStop[bank]));
+#ifdef DEBUG
+ printk("trident: stop voice on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
int DidChannelInterrupt( )
- Description: Check if interrupt channel occurred.
+ Description: Check if interrupt channel occurred.
- Parameters : trident - pointer to target device class for 4DWave.
+ Parameters : trident - pointer to target device class for 4DWave.
Return Value: TRUE if interrupt occurred, else FALSE.
---------------------------------------------------------------------------*/
-static int DidChannelInterrupt(struct trident_card * trident, int channel)
+static int trident_check_channel_interrupt(struct trident_card * trident, int channel)
{
- unsigned int ChanDwordCount = trident->ChanDwordCount;
- unsigned int x = channel >> 5;
- unsigned int dwMask = 1 << (channel & 0x1f);
+ unsigned int ChanDwordCount = NUM_BANKS;
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
ReadAint(&trident->ChRegs);
- return (trident->ChRegs.lpChAint[x] & dwMask) ? TRUE : FALSE;
+
+#ifdef DEBUG
+ if (trident->ChRegs.lpChAint[bank] & mask)
+ printk("trident: channel %d has interrupt\n", channel);
+#endif
+ return (trident->ChRegs.lpChAint[bank] & mask) ? TRUE : FALSE;
}
/*---------------------------------------------------------------------------
void AckChannelInterrupt( )
- Description: Acknowledge the interrupt bit for channel intrs.
+ Description: Acknowledge the interrupt bit for channel intrs.
- Parameters : trident - pointer to target device class for 4DWave.
+ Parameters : trident - pointer to target device class for 4DWave.
Return Value: None
---------------------------------------------------------------------------*/
-static void AckChannelInterrupt(struct trident_card * trident, int channel)
+static void trident_ack_channel_interrupt(struct trident_card * trident, int channel)
{
- unsigned int ChanDwordCount = trident->ChanDwordCount;
- unsigned int x = channel >> 5;
- unsigned int dwMask = 1 << (channel & 0x1f);
+ unsigned int ChanDwordCount = NUM_BANKS;
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
ReadAint(&trident->ChRegs);
- trident->ChRegs.lpChAint[x] &= dwMask;
+ trident->ChRegs.lpChAint[bank] &= mask;
IWriteAint(&trident->ChRegs);
}
/*---------------------------------------------------------------------------
- int LoadDeltaHw( unsigned int HwChannel, unsigned int Delta )
+ int trident_load_hw_delta( unsigned int HwChannel, unsigned int Delta )
Description: This routine writes Delta to the hardware.
- Parameters: Delta - data to write (2 Bytes only)
- HwChannel - Hardware channel to write to.
- trident - pointer to target device class for 4DWave.
+ Parameters: Delta - data to write (2 Bytes only)
+ HwChannel - Hardware channel to write to.
+ trident - pointer to target device class for 4DWave.
- Returns: TRUE if all goes well, else FALSE.
+ Returns: TRUE if all goes well, else FALSE.
---------------------------------------------------------------------------*/
-static int LoadDeltaHw(struct trident_card * trident, unsigned int HwChannel, unsigned int Delta)
+static int trident_load_hw_delta (struct trident_card * trident, unsigned int channel,
+ unsigned short delta)
{
+ /* select a channel for output */
+ outb(channel, TRID_REG(trident, T4D_LFO_GC_CIR));
- outb(HwChannel, TRID_REG(trident, T4D_LFO_GC_CIR));
-
- if (trident->card_type != TYPE_4DWAVE_NX) {
- outw((unsigned short) Delta, TRID_REG(trident, CH_DX_ESO_DELTA));
- }
- else // ID_4DWAVE_NX
+ switch (trident->pci_id)
{
- outb((unsigned char) Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
- outb((unsigned char) (Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3));
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ outw((u16) delta, TRID_REG(trident, CH_DX_ESO_DELTA));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ outb(delta & 0xff, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
+ outb((delta >> 8)& 0xff, TRID_REG(trident, CH_NX_DELTA_ESO + 3));
+ break;
+ default:
+ return FALSE;
}
-
return TRUE;
}
@@ -558,11 +670,11 @@
Description: This routine writes all required channel registers to hardware.
- Parameters: *Data - a pointer to the data to write (5 ULONGS always).
- HwChannel - Hardware channel to write to.
- trident - pointer to target device class for 4DWave.
+ Parameters: *Data - a pointer to the data to write (5 ULONGS always).
+ HwChannel - Hardware channel to write to.
+ trident - pointer to target device class for 4DWave.
- Returns: TRUE if all goes well, else FALSE.
+ Returns: TRUE if all goes well, else FALSE.
---------------------------------------------------------------------------*/
static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data, unsigned int HwChannel)
@@ -579,8 +691,9 @@
for (i = 0; i < ULONGSToDo; i++, Address += 4)
outl(ChanData[i], TRID_REG(trident, Address));
-
- M_printk("(trident) load virtual channel %d\n", HwChannel);
+#ifdef DEBUG
+ printk("(trident) load virtual channel %d\n", HwChannel);
+#endif
return TRUE;
}
@@ -588,13 +701,13 @@
trident_write_voice_regs
Description: This routine will write the 5 hardware channel registers
- to hardware.
+ to hardware.
- Paramters: trident - pointer to target device class for 4DWave.
- Channel - Real or Virtual channel number.
- Each register field.
+ Paramters: trident - pointer to target device class for 4DWave.
+ Channel - Real or Virtual channel number.
+ Each register field.
- Returns: TRUE if all goes well, else FALSE.
+ Returns: TRUE if all goes well, else FALSE.
---------------------------------------------------------------------------*/
int trident_write_voice_regs(struct trident_card * trident,
@@ -622,17 +735,19 @@
FmcRvolCvol = FMC_RVOL_CVOL & 0x0000ffff;
- if (trident->card_type != TYPE_4DWAVE_NX)
+ switch (trident->pci_id)
{
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
ChanData[0] = (CSO << 16) | (ALPHA_FMS & 0x0000ffff);
- ChanData[2] = (ESO << 16) | (DELTA & 0x0ffff);
+ ChanData[2] = (ESO << 16) | (DELTA & 0x0000ffff);
ChanData[3] = FmcRvolCvol;
- }
- else // ID_4DWAVE_NX
- {
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
ChanData[0] = (DELTA << 24) | (CSO & 0x00ffffff);
ChanData[2] = ((DELTA << 16) & 0xff000000) | (ESO & 0x00ffffff);
ChanData[3] = (ALPHA_FMS << 16) | FmcRvolCvol;
+ break;
}
LoadVirtualChannel(trident, ChanData, Channel);
@@ -663,19 +778,18 @@
Description: This routine will set the sample rate for playback.
- Paramters: trident - pointer to target device class for 4DWave.
- rate - desired sample rate
- set - actually write hardware if set is true.
+ Paramters: trident - pointer to target device class for 4DWave.
+ rate - desired sample rate
+ set - actually write hardware if set is true.
- Returns: The rate allowed by device.
+ Returns: The rate allowed by device.
---------------------------------------------------------------------------*/
static unsigned int trident_set_dac_rate(struct trident_state * trident,
- unsigned int rate, int set)
+ unsigned int rate, int set)
{
- unsigned int delta;
-
+ u16 delta;
if (rate > 48000)
rate = 48000;
@@ -683,25 +797,16 @@
rate = 4000;
delta = compute_rate(rate);
+ trident->ratedac = rate;
- if(set)
- {
- //Select channel window
- outb(trident->dma_dac.chan[1], TRID_REG(trident->card, T4D_LFO_GC_CIR));
-
- if (trident->card->card_type != TYPE_4DWAVE_NX)
- outw(delta,TRID_REG(trident->card,CH_DX_ESO_DELTA+2));
- else // ID_4DWAVE_NX
- {
- outb( delta & 0xff,TRID_REG(trident->card,CH_NX_DELTA_CSO));
- outb((delta>>8) & 0xff,TRID_REG(trident->card,CH_NX_DELTA_ESO));
- }
- }
-
- M_printk("(trident) called trident_set_dac_rate : rate = %d, set = %d delta = %4x\n",
- rate, set,delta);
+ if (set)
+ trident_load_hw_delta(trident->card, trident->dma_dac.chan[1],
+ delta);
+#ifdef DEBUG
+ printk("trident: called trident_set_dac_rate : rate = %d, "
+ "set = %d, delta = 0x%04x\n", rate, set, delta);
+#endif
- trident->ratedac = rate;
return rate;
}
@@ -710,29 +815,36 @@
Description: This routine will set the sample rate for capture.
- Paramters: trident - pointer to target device class for 4DWave.
- rate - desired sample rate
- set - actually write hardware if set is true.
+ Paramters: trident - pointer to target device class for 4DWave.
+ rate - desired sample rate
+ set - actually write hardware if set is true.
- Returns: The rate allowed by device.
+ Returns: The rate allowed by device.
---------------------------------------------------------------------------*/
static unsigned int trident_set_adc_rate(struct trident_state * trident,
- unsigned int rate,
- int set)
+ unsigned int rate, int set)
{
- //snd_printk("trid: called trident_set_adc_rate\n");
+ u16 delta;
+
if (rate > 48000)
rate = 48000;
if (rate < 4000)
rate = 4000;
- trident->rateadc = rate;
- /*
- * FIXME: hit the hardware
- */
+ delta = compute_rate(rate);
+ trident->ratedac = rate;
+#if 0 /* It seems that 4D-Wave can not use wave tables channels for recording */
+ if (set)
+ trident_load_hw_delta(trident->card, trident->dma_dac.chan[0],
+ delta);
+#endif
+#ifdef DEBUG
+ printk("trident: called trident_set_adc_rate : rate = %d, "
+ "set = %d, delta = 0x%04x\n", rate, set, delta);
+#endif
return rate;
}
@@ -761,94 +873,87 @@
return r;
}
-
-/* --------------------------------------------------------------------- */
-
-static struct trident_card *devs = NULL;
-
-/* --------------------------------------------------------------------- */
-
-
-/*
- * Trident AC97 codec programming interface.
- */
-
+/* Write AC97 mixer registers */
static void trident_ac97_set(struct trident_card *trident, u8 cmd, u16 val)
{
- unsigned int address, data;
- unsigned short count = 0xffff;
+ unsigned int address, mask, busy;
+ unsigned short count = 0xffff;
+ u32 data;
- data = ((unsigned long)val) << 16;
+ data = ((u32) val) << 16;
- if (trident->card_type != TYPE_4DWAVE_NX)
+ switch (trident->pci_id)
{
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ address = SI_AC97_WRITE;
+ mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
+ busy = SI_AC97_BUSY_WRITE;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
address = DX_ACR0_AC97_W;
- /* read AC-97 write register status */
- do
- {
- if ((inw(TRID_REG(trident,address))&0x8000) == 0)
- break;
- }
- while(count--);
-
- data |= (0x8000 | (cmd & 0x000000ff));
- }
- else // ID_4DWAVE_NX
- {
+ mask = busy = DX_AC97_BUSY_WRITE;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
address = NX_ACR1_AC97_W;
- /* read AC-97 write register status */
- do
- {
- if ((inw(TRID_REG(trident, address )) & 0x0800) == 0)
- break;
- }
- while (count--);
- data |= (0x0800 | (cmd & 0x000000ff));
+ mask = busy = NX_AC97_BUSY_WRITE;
+ break;
}
- if (count == 0)
- {
+
+ do {
+ if ((inw(TRID_REG(trident, address)) & busy) == 0)
+ break;
+ } while (count--);
+
+ data |= (mask | (cmd & AC97_REG_ADDR));
+
+ if (count == 0) {
printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
return;
}
-
outl(data, TRID_REG(trident, address));
}
+/* Read AC97 codec registers */
static u16 trident_ac97_get(struct trident_card *trident, u8 cmd)
{
- unsigned int data = 0;
+ unsigned int address, mask, busy;
unsigned short count = 0xffff;
+ u32 data;
- if (trident->card_type != TYPE_4DWAVE_NX)
- {
- data = (0x00008000L | (cmd & 0x000000ff));
- outl(data, TRID_REG(trident, DX_ACR1_AC97_R));
- do
- {
- data = inl(TRID_REG(trident, DX_ACR1_AC97_R));
- if ( ( data & 0x0008000 ) == 0 )
- break;
- }
- while(count--);
- }
- else // ID_4DWAVE_NX
+ switch (trident->pci_id)
{
- data = (0x00000800L | (cmd & 0x000000ff));
- outl(data, TRID_REG(trident, NX_ACR2_AC97_R_PRIMARY));
- do
- {
- data = inl(TRID_REG(trident, NX_ACR2_AC97_R_PRIMARY));
- if ( ( data & 0x00000C00 ) == 0 )
- break;
- }
- while(count--);
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ address = SI_AC97_READ;
+ mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
+ busy = SI_AC97_BUSY_READ;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ address = DX_ACR1_AC97_R;
+ mask = busy = DX_AC97_BUSY_READ;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ address = NX_ACR2_AC97_R_PRIMARY;
+ mask = NX_AC97_BUSY_READ;
+ busy = 0x0c00;
+ break;
}
- if ( count == 0 )
- {
- printk("trident: AC97 CODEC read timed out.\n");
+
+ data = (mask | (cmd & AC97_REG_ADDR));
+ outl(data, TRID_REG(trident, address));
+
+ do {
+ data = inl(TRID_REG(trident, address));
+ if ((data & busy) == 0)
+ break;
+ } while (count--);
+
+ if (count == 0) {
+ printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
data = 0;
}
- return ((unsigned short)(data >> 16));
+ return ((u16) (data >> 16));
}
/* OSS interface to the ac97s.. */
@@ -876,7 +981,7 @@
int mixer;
unsigned int value;
} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
- /* all values 0 -> 100 in bytes */
+ /* all values 0 -> 100 in bytes */
{SOUND_MIXER_VOLUME, 0x3232},
{SOUND_MIXER_BASS, 0x3232},
{SOUND_MIXER_TREBLE, 0x3232},
@@ -895,35 +1000,35 @@
unsigned char offset;
int scale;
} ac97_hw[SOUND_MIXER_NRDEVICES]= {
- [SOUND_MIXER_VOLUME] = {0x02,63},
- [SOUND_MIXER_BASS] = {0x08,15},
- [SOUND_MIXER_TREBLE] = {0x08,15},
- [SOUND_MIXER_SPEAKER] = {0x0a,15},
- [SOUND_MIXER_MIC] = {0x0e,31},
- [SOUND_MIXER_LINE] = {0x10,31},
- [SOUND_MIXER_CD] = {0x12,31},
- [SOUND_MIXER_VIDEO] = {0x14,31},
- [SOUND_MIXER_LINE1] = {0x16,31},
- [SOUND_MIXER_PCM] = {0x18,31},
- [SOUND_MIXER_IGAIN] = {0x1c,31}
+ [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63},
+ [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
+ [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31},
+ [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31},
+ [SOUND_MIXER_CD] = {AC97_CD_VOL, 31},
+ [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31},
+ [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31},
+ [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31},
+ [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31}
};
#if 0 /* *shrug* removed simply because we never used it.
- feel free to implement again if needed */
+ feel free to implement again if needed */
/* reads the given OSS mixer from the ac97
- the caller must have insured that the ac97 knows
- about that given mixer, and should be holding a
- spinlock for the card */
+ the caller must have insured that the ac97 knows
+ about that given mixer, and should be holding a
+ spinlock for the card */
static int ac97_read_mixer(struct trident_card *card, int mixer)
{
u16 val;
- int ret=0;
+ int ret = 0;
struct ac97_mixer_hw *mh = &ac97_hw[mixer];
val = trident_ac97_get(card , mh->offset);
- if(AC97_STEREO_MASK & (1<<mixer)) {
+ if (AC97_STEREO_MASK & (1<<mixer)) {
/* nice stereo mixers .. */
int left,right;
@@ -944,33 +1049,39 @@
} else if (mixer == SOUND_MIXER_MIC) {
ret = 100 - (((val & 0x1f) * 100) / mh->scale);
/* the low bit is optional in the tone sliders and masking
- it lets is avoid the 0xf 'bypass'.. */
+ it lets us avoid the 0xf 'bypass'.. */
} else if (mixer == SOUND_MIXER_BASS) {
ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
} else if (mixer == SOUND_MIXER_TREBLE) {
ret = 100 - (((val & 0xe) * 100) / mh->scale);
}
- printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
+#ifdef DEBUG
+ printk("trident: read OSS mixer %2d (ac97 register 0x%02x), "
+ "0x%04x -> 0x%04x\n", mixer, mh->offset, val, ret);
+#endif
return ret;
}
#endif
/* write the OSS encoded volume to the given OSS encoded mixer,
- again caller's job to make sure all is well in arg land,
- call with spinlock held */
-static void ac97_write_mixer(struct trident_card *card, int mixer, unsigned int left, unsigned int right)
+ again caller's job to make sure all is well in arg land,
+ call with spinlock held */
+static void ac97_write_mixer(struct trident_card *card, int mixer,
+ unsigned int left, unsigned int right)
{
- u16 val=0;
+ u16 val = 0;
struct ac97_mixer_hw *mh = &ac97_hw[mixer];
- printk("(trident) wrote ac97 mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
+#ifdef DEBUG
+ printk("trident: wrote OSS mixer %2d (ac97 register 0x%02x), "
+ "left vol:%2d, right vol:%2d:",
+ mixer, mh->offset, left, right);
+#endif
- if(AC97_STEREO_MASK & (1<<mixer)) {
+ if (AC97_STEREO_MASK & (1 << mixer)) {
/* stereo mixers */
-
-
if (mixer == SOUND_MIXER_IGAIN) {
right = (right * mh->scale) / 100;
left = (left * mh->scale) / 100;
@@ -980,25 +1091,31 @@
}
val = (left << 8) | right;
-
} else if (mixer == SOUND_MIXER_SPEAKER) {
val = (((100 - left) * mh->scale) / 100) << 1;
} else if (mixer == SOUND_MIXER_MIC) {
val = trident_ac97_get(card , mh->offset) & ~0x801f;
val |= (((100 - left) * mh->scale) / 100);
- /* the low bit is optional in the tone sliders and masking
- it lets us avoid the 0xf 'bypass'.. */
+ /* the low bit is optional in the tone sliders and masking
+ it lets us avoid the 0xf 'bypass'.. */
} else if (mixer == SOUND_MIXER_BASS) {
val = trident_ac97_get(card , mh->offset) & ~0x0f00;
val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (mixer == SOUND_MIXER_TREBLE) {
+ } else if (mixer == SOUND_MIXER_TREBLE) {
val = trident_ac97_get(card , mh->offset) & ~0x000f;
val |= (((100 - left) * mh->scale) / 100) & 0x000e;
}
+#ifdef DEBUG
+ printk(" 0x%04x", val);
+#endif
+
trident_ac97_set(card, mh->offset, val);
-
- printk(" -> %x\n",val);
+
+#ifdef DEBUG
+ val = trident_ac97_get(card, mh->offset);
+ printk(" -> 0x%04x\n", val);
+#endif
}
/* the following tables allow us to go from
@@ -1011,8 +1128,8 @@
AC97_REC_AUX,
AC97_REC_LINE,
AC97_REC_STEREO, /* combination of all enabled outputs.. */
- AC97_REC_MONO, /*.. or the mono equivalent */
- AC97_REC_PHONE
+ AC97_REC_MONO, /*.. or the mono equivalent */
+ AC97_REC_PHONE
};
static unsigned int ac97_rm2oss[] = {
@@ -1035,12 +1152,11 @@
};
/* read or write the recmask
- the ac97 can really have left and right recording
- inputs independantly set, but OSS doesn't seem to
- want us to express that to the user.
- the caller guarantees that we have a supported bit set,
- and they must be holding the card's spinlock */
-
+ the ac97 can really have left and right recording
+ inputs independantly set, but OSS doesn't seem to
+ want us to express that to the user.
+ the caller guarantees that we have a supported bit set,
+ and they must be holding the card's spinlock */
static int ac97_recmask_io(struct trident_card *card, int rw, int mask)
{
unsigned int val;
@@ -1052,125 +1168,91 @@
}
/* else, write the first set in the mask as the
- output */
+ output */
val = ffs(mask);
val = ac97_oss_rm[val-1];
val |= val << 8; /* set both channels */
-
- printk("trident: setting ac97 recmask to 0x%x\n",val);
-
- trident_ac97_set(card,0x1a,val);
+#ifdef DEBUG
+ printk("trident: setting ac97 recmask to 0x%x\n", val);
+#endif
+ trident_ac97_set(card, 0x1a, val);
return 0;
};
-/*
- * Generic AC97 codec initialisation. Need to check there are no
- * quirks for the Trident cards.
- */
-
+/* AC97 codec initialisation. */
static u16 trident_ac97_init(struct trident_card *trident)
{
- trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
- trident->mix.stereo_mixers = AC97_STEREO_MASK;
- trident->mix.record_sources = AC97_RECORD_MASK;
-/* trident->mix.read_mixer = ac97_read_mixer;*/
- trident->mix.write_mixer = ac97_write_mixer;
- trident->mix.recmask_io = ac97_recmask_io;
+ u16 id1, id2;
+ char *ac97_name = NULL;
+ int i;
- if(trident->card_type == TYPE_4DWAVE_NX)
+ /* initialize controller side of AC link */
+ switch (trident->pci_id)
{
- unsigned short VendorID1, VendorID2;
-
+ case PCI_DEVICE_ID_SI_7018:
+ /* disable AC97 GPIO interrupt */
+ outl(0x00, TRID_REG(trident, SI_AC97_GPIO));
+ /* stop AC97 cold reset process */
+ outl(0x00014000, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ /* playback on */
+ outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
outl(0x02, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
+ break;
+ }
- // 4 Speaker Codec initialization
- VendorID1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
- VendorID2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
-
- if( (VendorID1 == 0x8384) && (VendorID2 == 0x7608) )
- {
- // Sigmatel 9708.
-
- unsigned short TestReg;
- unsigned int DTemp;
-
- trident_ac97_set(trident, AC97_SIGMATEL_CIC1, 0xABBAL);
- trident_ac97_set(trident, AC97_SIGMATEL_CIC2, 0x1000L);
-
- TestReg = trident_ac97_get(trident, AC97_SIGMATEL_BIAS2);
-
- if( TestReg != 0x8000 ) // Errata Notice.
- {
- trident_ac97_set(trident, AC97_SIGMATEL_BIAS1, 0xABBAL );
- trident_ac97_set(trident, AC97_SIGMATEL_BIAS2, 0x0007L );
- }
- else // Newer version
- {
- trident_ac97_set(trident, AC97_SIGMATEL_CIC2, 0x1001L ); // recommended
- trident_ac97_set(trident, AC97_SIGMATEL_DAC2INVERT, 0x0008L );
- }
-
- trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
- trident_ac97_set( trident, AC97_HEADPHONE_VOL, 0x8000L );
-
- DTemp = (unsigned int)trident_ac97_get( trident, AC97_GENERAL_PURPOSE );
- trident_ac97_set( trident, AC97_GENERAL_PURPOSE, DTemp & 0x0000FDFFL ); // bit9 = 0.
-
- DTemp = (unsigned int)trident_ac97_get( trident, AC97_MIC_VOL );
- trident_ac97_set( trident, AC97_MIC_VOL, DTemp | 0x00008000L ); // bit15 = 1.
-
- DTemp = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
- outl(DTemp | 0x0010, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
-
- }
- else if((VendorID1 == 0x5452) && (VendorID2 == 0x4108) )
- { // TriTech TR28028
- trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
- trident_ac97_set( trident, AC97_EXTENDED_STATUS, 0x0000L );
- }
- else if((VendorID1 == 0x574D) &&
- (VendorID2 >= 0x4C00) && (VendorID2 <= 0x4C0f))
- { // Wolfson WM9704
- trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
- }
- else
- {
-#if 0
- printk("trident: No four Speaker Support with on board CODEC\n") ;
-#endif
+ /* get some information about our AC97 codec */
+ id1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
+ id2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
+ for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
+ if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+ ac97_name = snd_ac97_codec_ids[i].name;
+ break;
}
-
- // S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled
- outl(0x200004, TRID_REG(trident, NX_SPCSTATUS));
- // Enable S/PDIF out, 48khz only from ac97 fifo
- outb(0x28, TRID_REG(trident, NX_SPCTRL_SPCSO+3));
}
- else
- {
- outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
- }
+ if (ac97_name == NULL)
+ ac97_name = "Unknown";
+ printk(KERN_INFO "trident: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
+ id1, id2, ac97_name);
+
+ /* initialize volume level */
+ trident_ac97_set(trident, AC97_RESET, 0L);
+ trident_ac97_set(trident, AC97_MASTER_VOL_STEREO, 0L);
+ trident_ac97_set(trident, AC97_PCMOUT_VOL, 0L);
+
+ /* set appropriate masks and function pointers */
+ trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
+ trident->mix.stereo_mixers = AC97_STEREO_MASK;
+ trident->mix.record_sources = AC97_RECORD_MASK;
+ /* FIXME: trident->mix.read_mixer = ac97_read_mixer; */
+ trident->mix.write_mixer = ac97_write_mixer;
+ trident->mix.recmask_io = ac97_recmask_io;
+
return 0;
}
-
/* this only fixes the output apu mode to be later set by start_dac and
- company. output apu modes are set in trident_rec_setup */
+ company. output apu modes are set in trident_rec_setup */
static void set_fmt(struct trident_state *s, unsigned char mask, unsigned char data)
{
s->fmt = (s->fmt & mask) | data;
/* Set the chip ? */
}
-
-/*
- * Native play back driver
- */
-
/* the mode passed should be already shifted and masked */
+/* trident_play_setup: initialize channel for play back, mode specify the format of samples to
+ be played.
+ default values:
+*/
-static void trident_play_setup(struct trident_state *trident, int mode, u32 rate, void *buffer, int size)
+static void trident_play_setup(struct trident_state *trident, int mode, u32 rate,
+ void *buffer, int size)
{
unsigned int LBA;
unsigned int Delta;
@@ -1182,38 +1264,28 @@
unsigned int VOL;
unsigned int EC;
-
-
- /* set Loop Back Address */
+ /* set Loop Begin Address */
LBA = virt_to_bus(buffer);
-
Delta = compute_rate(rate);
- M_printk("(trident) rate, delta = %d %d\n", rate, Delta);
-
/* set ESO */
ESO = size;
if (mode & TRIDENT_FMT_16BIT)
ESO /= 2;
if (mode & TRIDENT_FMT_STEREO)
ESO /= 2;
-
ESO = ESO - 1;
- //snd_printk("trid: ESO = %d\n", ESO);
- /* set ctrl mode
- CTRL default: 8-bit (unsigned) mono, loop mode enabled
- */
CTRL = 0x00000001;
- if (mode & TRIDENT_FMT_16BIT)
- {
+ if (mode & TRIDENT_FMT_16BIT) {
CTRL |= 0x00000008; // 16-bit data
CTRL |= 0x00000002; // signed data
}
- if (mode&TRIDENT_FMT_STEREO)
+ if (mode & TRIDENT_FMT_STEREO)
CTRL |= 0x00000004; // stereo data
-
- //FMC_RVOL_CVOL = 0x0000c000;
+
+ /* FIXME: some difference between 4D and 7018 in FMC_RVOL_CVOL */
+ /* right vol: mute, ledt vol: mute */
FMC_RVOL_CVOL = 0x0000ffff;
GVSEL = 1;
PAN = 0;
@@ -1221,25 +1293,25 @@
EC = 0;
trident_write_voice_regs(trident->card,
- trident->dma_dac.chan[1],
- LBA,
- 0, /* cso */
- ESO,
- Delta,
- 0, /* alpha */
- FMC_RVOL_CVOL,
- GVSEL,
- PAN,
- VOL,
- CTRL,
- EC);
+ trident->dma_dac.chan[1],
+ LBA,
+ 0, /* cso */
+ ESO,
+ Delta,
+ 0, /* alpha */
+ FMC_RVOL_CVOL,
+ GVSEL,
+ PAN,
+ VOL,
+ CTRL,
+ EC);
}
/*
* Native record driver
*/
-
+/* FIXME: Not exammed yet */
/* again, passed mode is alrady shifted/masked */
static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate, void *buffer, int size)
@@ -1260,16 +1332,24 @@
unsigned int dwChanFlags;
struct trident_card *card = trident->card;
+#ifdef DEBUG
+ printk("trident: trident_rec_setup called\n");
+#endif
+
// Enable AC-97 ADC (capture), disable capture interrupt
- if (trident->card->card_type != TYPE_4DWAVE_NX)
+ switch (card->pci_id)
{
+ case PCI_DEVICE_ID_SI_7018:
+ /* for 7018, the ac97 is always in playback/record (duplex) mode */
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
bValue = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
outb(bValue | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- }
- else
- {
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
wValue = inw(TRID_REG(card, T4D_MISCINT));
outw(wValue | 0x1000, TRID_REG(card, T4D_MISCINT));
+ break;
}
// Initilize the channel and set channel Mode
@@ -1367,35 +1447,42 @@
}
-/* Playback pointer */
+/* get current playback pointer */
__inline__ unsigned int get_dmaa(struct trident_state *trident)
{
- unsigned int cso;
- unsigned int eso;
-
+ u32 cso;
+ u32 eso;
#if 0
+ /* FIXME: does this mean that FULL duplex is not supported ? */
if (!(trident->enable & ADC_RUNNING))
return 0;
#endif
-
outb(trident->dma_dac.chan[1], TRID_REG(trident->card, T4D_LFO_GC_CIR));
- if (trident->card->card_type != TYPE_4DWAVE_NX)
+ switch (trident->card->pci_id)
{
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ /* 16 bits ESO, CSO for 7018 and DX */
cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
eso = inw(TRID_REG(trident->card, CH_DX_ESO_DELTA + 2));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ /* 24 bits ESO, CSO for NX */
+ cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+ eso = inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
+ break;
+ default:
+ return 0;
}
- else // ID_4DWAVE_NX
- {
- cso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
- eso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
- }
- M_printk("(trident) get_dmaa: chip reported %d.%d\n", cso, eso);
- cso++;
+#ifdef DEBUG
+ printk("trident: get_dmaa: chip reported esc = %d, cso = %d\n", cso, eso);
+#endif
+ cso++;
+ /* ESO and CSO are in units of Samples, convert to byte offset */
if (cso > eso)
cso = eso;
-
if (trident->fmt & TRIDENT_FMT_16BIT)
cso *= 2;
if (trident->fmt & TRIDENT_FMT_STEREO)
@@ -1403,26 +1490,36 @@
return cso;
}
-/* Record pointer */
+/* get current recording pointer */
extern __inline__ unsigned get_dmac(struct trident_state *trident)
{
- unsigned int cso;
-
+ u32 cso;
+#if 0
+ /* FIXME: does this mean that FULL duplex is not supported ? */
if (!(trident->enable&DAC_RUNNING))
return 0;
-
+#endif
outb(trident->dma_adc.chan[0], TRID_REG(trident->card, T4D_LFO_GC_CIR));
- if (trident->card->card_type != TYPE_4DWAVE_NX) {
+ switch (trident->card->pci_id)
+ {
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ /* 16 bits ESO, CSO for 7018 and DX */
cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
- } else { // ID_4DWAVE_NX
- cso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ /* 24 bits ESO, CSO for NX */
+ cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+ break;
}
- printk("(trident) get_dmac: chip reported %d\n", cso);
-
+#ifdef DEBUG
+ printk("(trident) get_dmac: chip reported cso = %d\n", cso);
+#endif
cso++;
-
+ /* ESO and CSO are in units of Samples, convert to byte offset */
if (trident->fmt & TRIDENT_FMT_16BIT)
cso *= 2;
if (trident->fmt & TRIDENT_FMT_STEREO)
@@ -1430,24 +1527,13 @@
return cso;
}
-static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-static void trident_kick(unsigned long plop)
-{
- trident_interrupt(5, (void *)plop, NULL);
- debug_timer.expires=jiffies+1;
- add_timer(&debug_timer);
-}
-
/* Stop recording (lock held) */
-
extern inline void __stop_adc(struct trident_state *s)
{
struct trident_card *trident = s->card;
-
- M_printk("(trident) stopping ADC\n");
-
-
+#ifdef DEBUG
+ printk("(trident) stopping ADC\n");
+#endif
s->enable &= ~ADC_RUNNING;
trident_disable_voice_irq(trident, s->dma_adc.chan[0]);
outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
@@ -1471,9 +1557,9 @@
extern inline void __stop_dac(struct trident_state *s)
{
struct trident_card *trident = s->card;
-
- M_printk("(trident) stopping DAC\n");
-
+#ifdef DEBUG
+ printk("(trident) stopping DAC\n");
+#endif
//trident_stop_voice(trident, s->dma_dac.chan[0]);
//trident_disable_voice_irq(trident, s->dma_dac.chan[0]);
trident_stop_voice(trident, s->dma_dac.chan[1]);
@@ -1503,8 +1589,9 @@
trident_enable_voice_irq(trident, s->dma_dac.chan[1]);
trident_start_voice(trident, s->dma_dac.chan[1]);
//trident_start_voice(trident, s->dma_dac.chan[0]);
- M_printk("(trident) starting DAC\n");
-
+#ifdef DEBUG
+ printk("(trident) starting DAC\n");
+#endif
}
spin_unlock_irqrestore(&s->card->lock, flags);
}
@@ -1520,25 +1607,65 @@
trident_enable_voice_irq(s->card, s->dma_adc.chan[0]);
outb(s->bDMAStart, TRID_REG(s->card, T4D_SBCTRL_SBE2R_SBDD));
trident_start_voice(s->card, s->dma_adc.chan[0]);
- M_printk("(trident) starting ADC\n");
-
+#ifdef DEBUG
+ printk("(trident) starting ADC\n");
+#endif
}
spin_unlock_irqrestore(&s->card->lock, flags);
}
-/* --------------------------------------------------------------------- */
-
-/* we allocate both buffers at once */
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 2
+/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
+static int alloc_dmabuf(struct trident_state *state, unsigned rec)
+{
+ void *rawbuf;
+ int order;
+ unsigned long map, mapend;
+
+ /* alloc as big a chunk as we can, FIXME: is this necessary ?? */
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+ if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+ break;
+ if (!rawbuf)
+ return -ENOMEM;
+
+ /* for 4DWave and 7018, there are only 30 (31) siginifcan bits for Loop Begin Address
+ (LBA) which limits the address space to 1 (2) GB, bad T^2 design */
+ if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~0x3fffffff) {
+ printk(KERN_ERR "trident: DMA buffer beyond 1 GB; "
+ "bus address = 0x%lx, size = %ld\n",
+ virt_to_bus(rawbuf), PAGE_SIZE << order);
+ free_pages((unsigned long)rawbuf, order);
+ return -ENOMEM;
+ }
+
+ if (rec) {
+ state->dma_adc.ready = state->dma_adc.mapped = 0;
+ state->dma_adc.rawbuf = rawbuf;
+ state->dma_adc.buforder = order;
+ }
+ else {
+ state->dma_dac.ready = state->dma_dac.mapped = 0;
+ state->dma_dac.rawbuf = rawbuf;
+ state->dma_dac.buforder = order;
+ }
+
+ /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+ mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+ for (map = MAP_NR(rawbuf); map <= mapend; map++)
+ set_bit(PG_reserved, &mem_map[map].flags);
+
+ return 0;
+}
+
+/* free DMA buffer */
static void dealloc_dmabuf(struct dmabuf *db)
{
unsigned long map, mapend;
- if (db->rawbuf)
- {
- M_printk("(trident) freeing %p\n",db->rawbuf);
+ if (db->rawbuf) {
/* undo marking the pages as reserved */
mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
@@ -1549,72 +1676,37 @@
db->mapped = db->ready = 0;
}
-static int prog_dmabuf(struct trident_state *s, unsigned rec)
+static int prog_dmabuf(struct trident_state *state, unsigned rec)
{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- int order;
+ struct dmabuf *db = rec ? &state->dma_adc : &state->dma_dac;
+ unsigned rate = rec ? state->rateadc : state->ratedac;
unsigned bytepersec;
unsigned bufs;
- unsigned long map, mapend;
unsigned char fmt;
unsigned long flags;
+ int ret;
- spin_lock_irqsave(&s->card->lock, flags);
- fmt = s->fmt;
+ spin_lock_irqsave(&state->card->lock, flags);
+ fmt = state->fmt;
if (rec) {
- s->enable &= ~TRIDENT_ENABLE_RE;
+ state->enable &= ~TRIDENT_ENABLE_RE;
fmt >>= TRIDENT_ADC_SHIFT;
} else {
- s->enable &= ~TRIDENT_ENABLE_PE;
+ state->enable &= ~TRIDENT_ENABLE_PE;
fmt >>= TRIDENT_DAC_SHIFT;
}
- spin_unlock_irqrestore(&s->card->lock, flags);
- fmt &= TRIDENT_FMT_MASK;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
- if (!db->rawbuf) {
- void *rawbuf;
- /* haha, this thing is hacked to hell and back.
- this is so ugly. */
- s->dma_dac.ready = s->dma_dac.mapped = 0;
- s->dma_adc.ready = s->dma_adc.mapped = 0;
-
- /* alloc as big a chunk as we can */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
-
- break;
+ spin_unlock_irqrestore(&state->card->lock, flags);
- if (!rawbuf)
- return -ENOMEM;
-
-
- /* we allocated both buffers */
- s->dma_adc.rawbuf = rawbuf;
- s->dma_dac.rawbuf = rawbuf + ( PAGE_SIZE << (order - 1) );
-
- M_printk("(trident) allocated %ld bytes at %p\n",PAGE_SIZE<<order, db->rawbuf);
-
- s->dma_adc.buforder = s->dma_dac.buforder = order - 1;
+ fmt &= TRIDENT_FMT_MASK;
- /* XXX these checks are silly now */
-#if 0
- if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << order) - 1)) & ~0xffff)
- printk(KERN_DEBUG "trident: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << order);
+ db->hwptr = db->swptr = db->total_bytes = 0;
+ db->count = db->error = db->endcleared = 0;
-#endif
- if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << order) - 1) & ~0xffffff)
- M_printk(KERN_DEBUG "(trident) DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << order);
+ /* allocate DMA buffer if not allocated yet */
+ if (!db->rawbuf)
+ if ((ret = alloc_dmabuf(state, rec)))
+ return ret;
- /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
- mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << order) - 1);
- for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
- set_bit(PG_reserved, &mem_map[map].flags);
- }
bytepersec = rate << sample_shift[fmt];
bufs = PAGE_SIZE << db->buforder;
if (db->ossfragshift) {
@@ -1623,13 +1715,8 @@
else
db->fragshift = db->ossfragshift;
} else {
- /* lets hand out reasonable big ass buffers by default */
+ /* lets hand out reasonable big ass buffers by default */
db->fragshift = (db->buforder + PAGE_SHIFT -2);
-#if 0
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
-#endif
}
db->numfrag = bufs >> db->fragshift;
while (db->numfrag < 4 && db->fragshift > 3) {
@@ -1644,22 +1731,23 @@
memset(db->rawbuf, (fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, db->dmasize);
- spin_lock_irqsave(&s->card->lock, flags);
+ spin_lock_irqsave(&state->card->lock, flags);
if (rec) {
- trident_rec_setup(s, fmt, s->rateadc,
- db->rawbuf, db->numfrag << db->fragshift);
+ trident_rec_setup(state, fmt, state->rateadc,
+ db->rawbuf, db->numfrag << db->fragshift);
} else {
- trident_play_setup(s, fmt, s->ratedac,
- db->rawbuf, db->numfrag << db->fragshift);
+ trident_play_setup(state, fmt, state->ratedac,
+ db->rawbuf, db->numfrag << db->fragshift);
}
- spin_unlock_irqrestore(&s->card->lock, flags);
+ spin_unlock_irqrestore(&state->card->lock, flags);
+
+ /* set the ready flag for the dma buffer */
db->ready = 1;
return 0;
}
/* only called by trident_write */
-
extern __inline__ void clear_advance(struct trident_state *s)
{
unsigned char c = ((s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_16BIT) ? 0 : 0x80;
@@ -1701,13 +1789,16 @@
}
}
}
+
/* update DAC pointer */
if (s->dma_dac.ready)
{
/* this is so gross. */
hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize;
diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- M_printk("(trident) updating dac: hwptr: %d diff: %d\n",hwptr,diff);
+#ifdef DEBUG
+ printk("(trident) updating dac: hwptr: %d diff: %d\n",hwptr,diff);
+#endif
s->dma_dac.hwptr = hwptr;
s->dma_dac.total_bytes += diff;
if (s->dma_dac.mapped)
@@ -1719,7 +1810,9 @@
else
{
s->dma_dac.count -= diff;
- M_printk("(trident) trident_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count);
+#ifdef DEBUG
+ printk("(trident) trident_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count);
+#endif
if (s->dma_dac.count <= 0)
{
s->enable &= ~TRIDENT_ENABLE_PE;
@@ -1747,94 +1840,76 @@
/*
* Trident interrupt handlers.
*/
-
static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct trident_state *s;
- struct trident_card *c = (struct trident_card *)dev_id;
+ struct trident_state *state;
+ struct trident_card *card = (struct trident_card *)dev_id;
int i;
u32 event;
- spin_lock(&c->lock);
-
- event = inl(TRID_REG(c, T4D_MISCINT));
-
-// if(event & 0x28)
-// printk("IRQ %04X (%08lX, %08lX)\n", event, c->iobase, TRID_REG(c, T4D_MISCINT));
-
- if(event & 8)
- {
- /* Midi - TODO */
- }
-
- if(event & 0x20)
- {
- /*
- * Update the pointers for all channels we are running.
- */
-
- for(i=0;i<NR_DSPS;i++)
- {
- s=&c->channels[i];
- if(DidChannelInterrupt(c, i))
- {
- AckChannelInterrupt(c,i);
- if(s->dev_audio != -1)
- trident_update_ptr(s);
- else
- {
+ spin_lock(&card->lock);
+ event = inl(TRID_REG(card, T4D_MISCINT));
+
+#ifdef DEBUG
+ printk("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
+#endif
+
+ if (event & ADDRESS_IRQ) {
+ /* Update the pointers for all channels we are running. */
+ /* the index variable i is the main bug make the original driver crash,
+ the code mix "software" channel with "hardware" channel */
+ for (i = 0; i < NR_DSPS; i++) {
+ state = &card->channels[i];
+ if (trident_check_channel_interrupt(card, 63 - i)) {
+ trident_ack_channel_interrupt(card, 63 - i);
+ if (state->dev_audio != -1)
+ trident_update_ptr(state);
+ else {
/* Spurious ? */
- M_printk("(trident) spurious channel irq %d.\n", i);
- trident_stop_voice(c, i);
- trident_disable_voice_irq(c,i);
+ printk("trident: spurious channel irq %d.\n",
+ 63 - i);
+ trident_stop_voice(card, i);
+ trident_disable_voice_irq(card, i);
}
}
}
-
- }
- spin_unlock(&c->lock);
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
+ }
-#define VALIDATE_MAGIC(FOO,MAG) \
-({ \
- if (!(FOO) || (FOO)->magic != MAG) { \
- printk(invalid_magic,__FUNCTION__); \
- return -ENXIO; \
- } \
-})
+ if (event & SB_IRQ){
+ /* Midi - TODO */
+ }
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+ /* manually clear interrupt status, bad hardware design, balme T^2 */
+ outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
+ TRID_REG(card, T4D_MISCINT));
+ spin_unlock(&card->lock);
+}
static void set_mixer(struct trident_card *card,unsigned int mixer, unsigned int val )
{
unsigned int left,right;
+
/* cleanse input a little */
right = ((val >> 8) & 0xff) ;
left = (val & 0xff) ;
- if(right > 100) right = 100;
- if(left > 100) left = 100;
+ if (right > 100) right = 100;
+ if (left > 100) left = 100;
- card->mix.mixer_state[mixer]=(right << 8) | left;
- card->mix.write_mixer(card,mixer,left,right);
+ card->mix.mixer_state[mixer] = (right << 8) | left;
+ card->mix.write_mixer(card, mixer, left, right);
}
static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned long arg)
{
unsigned long flags;
- int i, val=0;
+ int i, val = 0;
VALIDATE_CARD(card);
- if (cmd == SOUND_MIXER_INFO) {
+ if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, card_names[card->card_type], sizeof(info.id));
- strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+ strncpy(info.id, card->pci_info->name, sizeof(info.id));
+ strncpy(info.name, card->pci_info->name, sizeof(info.name));
info.modify_counter = card->mix.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -1842,23 +1917,23 @@
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, card_names[card->card_type], sizeof(info.id));
- strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+ strncpy(info.id, card->pci_info->name, sizeof(info.id));
+ strncpy(info.name, card->pci_info->name, sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
}
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
+ return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* give them the current record source */
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
- if(!card->mix.recmask_io) {
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* give them the current record source */
+ if (!card->mix.recmask_io) {
val = 0;
} else {
spin_lock_irqsave(&card->lock, flags);
@@ -1866,83 +1941,71 @@
spin_unlock_irqrestore(&card->lock, flags);
}
break;
-
- case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
+
+ case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
val = card->mix.supported_mixers;
break;
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+ case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
val = card->mix.record_sources;
break;
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+
+ case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
val = card->mix.stereo_mixers;
break;
-
- case SOUND_MIXER_CAPS:
+
+ case SOUND_MIXER_CAPS:
val = SOUND_CAP_EXCL_INPUT;
break;
default: /* read a specific mixer */
i = _IOC_NR(cmd);
- if ( ! supported_mixer(card,i))
+ if (!supported_mixer(card,i))
return -EINVAL;
/* do we ever want to touch the hardware? */
-/* spin_lock_irqsave(&s->lock, flags);
+ /* spin_lock_irqsave(&s->lock, flags);
val = card->mix.read_mixer(card,i);
spin_unlock_irqrestore(&s->lock, flags);*/
val = card->mix.mixer_state[i];
-/* printk("returned 0x%x for mixer %d\n",val,i);*/
-
+ /* printk("returned 0x%x for mixer %d\n",val,i);*/
break;
}
return put_user(val,(int *)arg);
}
-
- if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
- return -EINVAL;
-
- card->mix.modcnt++;
-
- get_user_ret(val, (int *)arg, -EFAULT);
-
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (!card->mix.recmask_io) return -EINVAL;
- if(! (val &= card->mix.record_sources)) return -EINVAL;
+ if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
+ card->mix.modcnt++;
+ get_user_ret(val, (int *)arg, -EFAULT);
+
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ if (!card->mix.recmask_io) return -EINVAL;
+ if (!(val &= card->mix.record_sources)) return -EINVAL;
+
+ spin_lock_irqsave(&card->lock, flags);
+ card->mix.recmask_io(card, 0, val);
+ spin_unlock_irqrestore(&card->lock, flags);
- spin_lock_irqsave(&card->lock, flags);
- card->mix.recmask_io(card,0,val);
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
+ return 0;
+ default: /* write a specific mixer */
+ i = _IOC_NR(cmd);
- if ( ! supported_mixer(card,i))
- return -EINVAL;
+ if (!supported_mixer(card, i))
+ return -EINVAL;
- spin_lock_irqsave(&card->lock, flags);
- set_mixer(card,i,val);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
+ set_mixer(card, i, val);
+ spin_unlock_irqrestore(&card->lock, flags);
- return 0;
+ return 0;
+ }
}
+ return -EINVAL;
}
-/* --------------------------------------------------------------------- */
-
-static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
-/* --------------------------------------------------------------------- */
-
static int trident_open_mixdev(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
@@ -1954,6 +2017,7 @@
return -ENODEV;
file->private_data = card;
+
//FIXME put back in
//MOD_INC_USE_COUNT;
return 0;
@@ -1970,7 +2034,8 @@
return 0;
}
-static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
{
struct trident_card *card = (struct trident_card *)file->private_data;
@@ -1979,6 +2044,11 @@
return mixer_ioctl(card, cmd, arg);
}
+static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
static /*const*/ struct file_operations trident_mixer_fops = {
&trident_llseek,
NULL, /* read */
@@ -1997,11 +2067,13 @@
NULL, /* lock */
};
-/* --------------------------------------------------------------------- */
-
+/* drain the DAC buffer
+ FIXME: This function will block (forever ??) when using
+ XMMS Qsound plugin and direct cat sample.wav > /dev/dsp
+ This behavior is when drain_dac is called by trident_release. */
static int drain_dac(struct trident_state *s, int nonblock)
{
- DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int count;
signed long tmo;
@@ -2011,8 +2083,7 @@
current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;)
- {
+ for (;;) {
spin_lock_irqsave(&s->card->lock, flags);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->card->lock, flags);
@@ -2023,20 +2094,20 @@
if (signal_pending(current))
break;
- if (nonblock)
- {
+ if (nonblock) {
remove_wait_queue(&s->dma_dac.wait, &wait);
current->state = TASK_RUNNING;
return -EBUSY;
}
-
+
tmo = (count * HZ) / s->ratedac;
tmo >>= sample_shift[(s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK];
- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
- or something. who cares. - zach */
+ /* XXX this is just broken. someone is waking us up alot,
+ or schedule_timeout is broken.
+ or something. who cares. - zach */
if (!schedule_timeout(tmo ? tmo : 1) && tmo)
- printk(KERN_DEBUG "trident: dma timed out?? %ld\n",jiffies);
+ printk(KERN_ERR "trident: dma timed out?? %ld\n", jiffies);
}
remove_wait_queue(&s->dma_dac.wait, &wait);
current->state = TASK_RUNNING;
@@ -2045,82 +2116,86 @@
return 0;
}
-/* --------------------------------------------------------------------- */
-
/* in this loop, dma_adc.count signifies the amount of data thats waiting
- to be copied to the user's buffer. it is filled by the interrupt
- handler and drained by this loop. */
+ to be copied to the user's buffer. it is filled by the interrupt
+ handler and drained by this loop. */
static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
+ struct trident_state *state = (struct trident_state *)file->private_data;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
- VALIDATE_STATE(s);
+ VALIDATE_STATE(state);
if (ppos != &file->f_pos)
return -ESPIPE;
- if (s->dma_adc.mapped)
+ if (state->dma_adc.mapped)
return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
return ret;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
ret = 0;
while (count > 0) {
- spin_lock_irqsave(&s->card->lock, flags);
+ spin_lock_irqsave(&state->card->lock, flags);
/* remember, all these things are expressed in bytes to be
- sent to the user.. hence the evil / 2 down below */
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ sent to the user.. hence the evil / 2 down below */
+ swptr = state->dma_adc.swptr;
+ cnt = state->dma_adc.dmasize - swptr;
+ if (state->dma_adc.count < cnt)
+ cnt = state->dma_adc.count;
+ spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- {
+ start_adc(state);
+ if (file->f_flags & O_NONBLOCK) {
ret = ret ? ret : -EAGAIN;
return ret;
}
- if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
- M_printk(KERN_DEBUG "(trident) read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- spin_lock_irqsave(&s->card->lock, flags);
-// set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ if (!interruptible_sleep_on_timeout(&state->dma_adc.wait, HZ)) {
+ printk(KERN_DEBUG "(trident) read: chip lockup? "
+ "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ state->dma_adc.dmasize,
+ state->dma_adc.fragsize,
+ state->dma_adc.count,
+ state->dma_adc.hwptr,
+ state->dma_adc.swptr);
+ stop_adc(state);
+
+ spin_lock_irqsave(&state->card->lock, flags);
+ /*set_dmac(s, virt_to_bus(s->dma_adc.rawbuf),
+ s->dma_adc.numfrag << s->dma_adc.fragshift); */
+ state->dma_adc.count = 0;
+ state->dma_adc.hwptr = 0;
+ state->dma_adc.swptr = 0;
+ spin_unlock_irqrestore(&state->card->lock, flags);
}
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
ret = ret ? ret : -ERESTARTSYS;
return ret;
}
continue;
}
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+ if (copy_to_user(buffer, state->dma_adc.rawbuf + swptr, cnt)) {
ret = ret ? ret : -EFAULT;
return ret;
}
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->card->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ swptr = (swptr + cnt) % state->dma_adc.dmasize;
+ spin_lock_irqsave(&state->card->lock, flags);
+ state->dma_adc.swptr = swptr;
+ state->dma_adc.count -= cnt;
+ spin_unlock_irqrestore(&state->card->lock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
- start_adc(s);
+ start_adc(state);
}
return ret;
@@ -2128,92 +2203,92 @@
static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
+ struct trident_state *state = (struct trident_state *)file->private_data;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
- int mode = (s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
+ int mode = (state->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
- M_printk("(trident) trident_write: count %d\n", count);
-
- VALIDATE_STATE(s);
+#ifdef DEBUG
+ printk("(trident) trident_write: count %d\n", count);
+#endif
+
+ VALIDATE_STATE(state);
if (ppos != &file->f_pos)
return -ESPIPE;
- if (s->dma_dac.mapped)
+ if (state->dma_dac.mapped)
return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
ret = 0;
while (count > 0) {
- spin_lock_irqsave(&s->card->lock, flags);
-
- if (s->dma_dac.count < 0)
- {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
-
- cnt = s->dma_dac.dmasize-swptr;
-
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
- spin_unlock_irqrestore(&s->card->lock, flags);
+ spin_lock_irqsave(&state->card->lock, flags);
+ if (state->dma_dac.count < 0) {
+ state->dma_dac.count = 0;
+ state->dma_dac.swptr = state->dma_dac.hwptr;
+ }
+ swptr = state->dma_dac.swptr;
+ cnt = state->dma_dac.dmasize - swptr;
+ if (state->dma_dac.count + cnt > state->dma_dac.dmasize)
+ cnt = state->dma_dac.dmasize - state->dma_dac.count;
+ spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
cnt = count;
-
- if (cnt <= 0)
- {
+ if (cnt <= 0) {
/* buffer is full, wait for it to be played */
- start_dac(s);
- if (file->f_flags & O_NONBLOCK)
- {
- if(!ret) ret = -EAGAIN;
+ start_dac(state);
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret) ret = -EAGAIN;
return ret;
}
- if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ))
- {
- M_printk(KERN_DEBUG
- "trident: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr,
- s->dma_dac.swptr);
- stop_dac(s);
- spin_lock_irqsave(&s->card->lock, flags);
-// set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ if (!interruptible_sleep_on_timeout(&state->dma_dac.wait, HZ)) {
+ printk(KERN_DEBUG
+ "trident: write: chip lockup? "
+ "dmasz %u fragsz %u count %i "
+ "hwptr %u swptr %u\n",
+ state->dma_dac.dmasize,
+ state->dma_dac.fragsize,
+ state->dma_dac.count,
+ state->dma_dac.hwptr,
+ state->dma_dac.swptr);
+ stop_dac(state);
+ spin_lock_irqsave(&state->card->lock, flags);
+ /* set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf),
+ s->dma_dac.numfrag << s->dma_dac.fragshift); */
+ state->dma_dac.count = 0;
+ state->dma_dac.hwptr = 0;
+ state->dma_dac.swptr = 0;
+ spin_unlock_irqrestore(&state->card->lock, flags);
}
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
if (!ret) ret = -ERESTARTSYS;
return ret;
}
continue;
}
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
- {
+ if (copy_from_user(state->dma_dac.rawbuf + swptr, buffer, cnt)) {
if (!ret)
ret = -EFAULT;
return ret;
}
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+ swptr = (swptr + cnt) % state->dma_dac.dmasize;
+
+ spin_lock_irqsave(&state->card->lock, flags);
+ state->dma_dac.swptr = swptr;
+ state->dma_dac.count += cnt;
+ state->dma_dac.endcleared = 0;
+ spin_unlock_irqrestore(&state->card->lock, flags);
- spin_lock_irqsave(&s->card->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->card->lock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
- start_dac(s);
+ start_dac(state);
}
return ret;
}
@@ -2259,11 +2334,11 @@
VALIDATE_STATE(s);
if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
+ if ((ret = prog_dmabuf(s, 0)) != 0)
return ret;
db = &s->dma_dac;
} else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
+ if ((ret = prog_dmabuf(s, 1)) != 0)
return ret;
db = &s->dma_adc;
} else
@@ -2284,336 +2359,315 @@
{
struct trident_state *s = (struct trident_state *)file->private_data;
unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
+ audio_buf_info abinfo;
+ count_info cinfo;
int val, mapped, ret;
unsigned char fmtm, fmtd;
-/* printk("trident: trident_ioctl: cmd %d\n", cmd);*/
-
VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+ mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
switch (cmd)
{
- case OSS_GETVERSION:
+ case OSS_GETVERSION:
return put_user(SOUND_VERSION, (int *)arg);
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, file->f_flags & O_NONBLOCK);
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ synchronize_irq();
+ s->dma_dac.swptr = s->dma_dac.hwptr = 0;
+ s->dma_dac.count = s->dma_dac.total_bytes = 0;
+ }
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ synchronize_irq();
+ s->dma_adc.swptr = s->dma_adc.hwptr = 0;
+ s->dma_adc.count = s->dma_adc.total_bytes = 0;
+ }
return 0;
- case SNDCTL_DSP_SETDUPLEX:
- /* XXX fix */
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(s, file->f_flags & O_NONBLOCK);
return 0;
- case SNDCTL_DSP_GETCAPS:
- return put_user(0/*DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP*/, (int *)arg);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- synchronize_irq();
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ)
- {
+ case SNDCTL_DSP_SPEED:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val >= 0) {
+ if (file->f_mode & FMODE_READ) {
stop_adc(s);
- synchronize_irq();
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+ s->dma_adc.ready = 0;
+ trident_set_adc_rate(s, val, 1);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ trident_set_dac_rate(s, val, 1);
}
+ }
+ return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac,
+ (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ fmtd = 0;
+ fmtm = ~0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ if (val)
+ fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+ else
+ fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val)
+ fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ else
+ fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+ }
+ set_fmt(s, fmtm, fmtd);
return 0;
- case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val >= 0)
- {
- if (file->f_mode & FMODE_READ)
- {
- stop_adc(s);
- s->dma_adc.ready = 0;
- trident_set_adc_rate(s, val, 1);
- }
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- s->dma_dac.ready = 0;
- trident_set_dac_rate(s, val, 1);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE) {
+ if ((val = prog_dmabuf(s, 0)))
+ return val;
+ return put_user(s->dma_dac.fragsize, (int *)arg);
+ }
+ if ((val = prog_dmabuf(s, 1)))
+ return val;
+ return put_user(s->dma_adc.fragsize, (int *)arg);
- case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != AFMT_QUERY) {
fmtd = 0;
fmtm = ~0;
- if (file->f_mode & FMODE_READ)
- {
+ if (file->f_mode & FMODE_READ) {
stop_adc(s);
s->dma_adc.ready = 0;
- if (val)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+ /* fixed at 16bit for now */
+ fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
+#if 0
+ if (val == AFMT_S16_LE)
+ fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+ fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
+#endif
}
- if (file->f_mode & FMODE_WRITE)
- {
+ if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
s->dma_dac.ready = 0;
- if (val)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ if (val == AFMT_S16_LE)
+ fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+ fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
}
set_fmt(s, fmtm, fmtd);
+ }
+ return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
+ (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ?
+ AFMT_S16_LE : AFMT_S8, (int *)arg);
+
+ case SNDCTL_DSP_CHANNELS:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 0) {
+ fmtd = 0;
+ fmtm = ~0;
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val != 0)
- {
- fmtd = 0;
- fmtm = ~0;
-
- if (file->f_mode & FMODE_READ)
- {
+ if (file->f_mode & FMODE_READ) {
stop_adc(s);
s->dma_adc.ready = 0;
if (val >= 2)
fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
else
fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
- }
+ }
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
- else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val >= 2)
+ fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ else
+ fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
}
+ set_fmt(s, fmtm, fmtd);
+ }
return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+ (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+ case SNDCTL_DSP_POST:
+ return 0;
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SUBDIVIDE:
+ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+ (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+ return -EINVAL;
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 1 && val != 2 && val != 4)
+ return -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ s->dma_adc.subdivision = val;
+ if (file->f_mode & FMODE_WRITE)
+ s->dma_dac.subdivision = val;
+ return 0;
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val != AFMT_QUERY)
- {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ)
- {
- stop_adc(s);
- s->dma_adc.ready = 0;
- /* fixed at 16bit for now */
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
-#if 0
- if (val == AFMT_S16_LE)
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
- else
- fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
-#endif
- }
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
- else
- fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ?
- AFMT_S16_LE : AFMT_S8, (int *)arg);
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ s->dma_adc.ossfragshift = val & 0xffff;
+ s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_adc.ossfragshift < 4)
+ s->dma_adc.ossfragshift = 4;
+ if (s->dma_adc.ossfragshift > 15)
+ s->dma_adc.ossfragshift = 15;
+ if (s->dma_adc.ossmaxfrags < 4)
+ s->dma_adc.ossmaxfrags = 4;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ s->dma_dac.ossfragshift = val & 0xffff;
+ s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_dac.ossfragshift < 4)
+ s->dma_dac.ossfragshift = 4;
+ if (s->dma_dac.ossfragshift > 15)
+ s->dma_dac.ossfragshift = 15;
+ if (s->dma_dac.ossmaxfrags < 4)
+ s->dma_dac.ossmaxfrags = 4;
+ }
+ return 0;
- case SNDCTL_DSP_POST:
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(0/* DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP */,
+ (int *)arg);
+
+ case SNDCTL_DSP_SETDUPLEX:
+ /* XXX fix */
return 0;
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE)
- val |= PCM_ENABLE_OUTPUT;
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE)
+ val |= PCM_ENABLE_OUTPUT;
return put_user(val, (int *)arg);
- case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (file->f_mode & FMODE_READ)
- {
- if (val & PCM_ENABLE_INPUT)
- {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- start_adc(s);
- }
- else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE)
- {
- if (val & PCM_ENABLE_OUTPUT)
- {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- start_dac(s);
- }
- else
- stop_dac(s);
- }
+ case SNDCTL_DSP_SETTRIGGER:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
+ start_adc(s);
+ }
+ else
+ stop_adc(s);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
+ start_dac(s);
+ }
+ else
+ stop_dac(s);
+ }
return 0;
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
+ return val;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ abinfo.fragsize = s->dma_dac.fragsize;
+ abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ abinfo.fragstotal = s->dma_dac.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
+ if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
return val;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ abinfo.fragsize = s->dma_adc.fragsize;
+ abinfo.bytes = s->dma_adc.count;
+ abinfo.fragstotal = s->dma_adc.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
return 0;
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ val = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return put_user(val, (int *)arg);
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ cinfo.bytes = s->dma_adc.total_bytes;
+ cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ cinfo.ptr = s->dma_adc.hwptr;
+ if (s->dma_adc.mapped)
+ s->dma_adc.count &= s->dma_adc.fragsize-1;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->card->lock, flags);
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ cinfo.bytes = s->dma_dac.total_bytes;
+ cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ cinfo.ptr = s->dma_dac.hwptr;
+ if (s->dma_dac.mapped)
+ s->dma_dac.count &= s->dma_dac.fragsize-1;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE)
- {
- if ((val = prog_dmabuf(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, (int *)arg);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, (int *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (file->f_mode & FMODE_READ)
- {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE)
- {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
+ case SOUND_PCM_READ_RATE:
return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
- case SOUND_PCM_READ_CHANNELS:
+ case SOUND_PCM_READ_CHANNELS:
return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
-
- case SOUND_PCM_READ_BITS:
+ (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
+ (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_FILTER:
return -EINVAL;
-
+
}
return -EINVAL;
}
@@ -2621,74 +2675,74 @@
static int trident_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
- struct trident_card *c = devs;
- struct trident_state *s = NULL, *sp;
+ struct trident_card *card = devs;
+ struct trident_state *state = NULL, *sp;
int i;
unsigned char fmtm = ~0, fmts = 0;
- /*
- * Scan the cards and find the channel. We only
- * do this at open time so it is ok
- */
-
- while (c!=NULL)
- {
- for(i=0;i<NR_DSPS;i++)
- {
- sp=&c->channels[i];
- if(sp->dev_audio < 0)
+ /* Scan the cards and find the channel.
+ We only do this at open time so it is ok */
+ while (card != NULL) {
+ for (i = 0; i < NR_DSPS; i++) {
+ sp = &card->channels[i];
+ if (sp->dev_audio < 0)
continue;
- if((sp->dev_audio ^ minor) & ~0xf)
+ if ((sp->dev_audio ^ minor) & ~0xf)
continue;
- s=sp;
+ state = sp;
}
- c=c->next;
+ card = card->next;
}
-
- if (!s)
+
+ if (!state)
return -ENODEV;
-
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- down(&s->open_sem);
- while (s->open_mode & file->f_mode)
- {
- if (file->f_flags & O_NONBLOCK)
- {
- up(&s->open_sem);
+
+ VALIDATE_STATE(state);
+ file->private_data = state;
+
+ down(&state->open_sem);
+
+ while (state->open_mode & file->f_mode) {
+ /* the channel has been open for the same mode before */
+ if (file->f_flags & O_NONBLOCK) {
+ /* Non-blocking mode, return immediately */
+ up(&state->open_sem);
return -EWOULDBLOCK;
}
- up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ up(&state->open_sem);
+ /* blocking, wait for device to become free */
+ interruptible_sleep_on(&state->open_wait);
if (signal_pending(current))
return -ERESTARTSYS;
- down(&s->open_sem);
+ down(&state->open_sem);
}
- if (file->f_mode & FMODE_READ)
- {
-/*
- fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
+
+ if (file->f_mode & FMODE_READ) {
+ /* fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
if ((minor & 0xf) == SND_DEV_DSP16)
fmts |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; */
fmtm = (TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- trident_set_adc_rate(s, 8000, 0);
+ state->dma_adc.ossfragshift = 0;
+ state->dma_adc.ossmaxfrags = 0;
+ state->dma_adc.subdivision = 0;
+ trident_set_adc_rate(state, 8000, 0);
}
- if (file->f_mode & FMODE_WRITE)
- {
+ if (file->f_mode & FMODE_WRITE) {
fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_DAC_SHIFT);
if ((minor & 0xf) == SND_DEV_DSP16)
fmts |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- trident_set_dac_rate(s, 8000, 1);
+ state->dma_dac.ossfragshift = 0;
+ state->dma_dac.ossmaxfrags = 0;
+ state->dma_dac.subdivision = 0;
+ trident_set_dac_rate(state, 8000, 1);
}
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ set_fmt(state, fmtm, fmts);
+ state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+
+ up(&state->open_sem);
- up(&s->open_sem);
//FIXME put back in
//MOD_INC_USE_COUNT;
return 0;
@@ -2696,27 +2750,28 @@
static int trident_release(struct inode *inode, struct file *file)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
+ struct trident_state *state = (struct trident_state *)file->private_data;
- VALIDATE_STATE(s);
+ VALIDATE_STATE(state);
if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- down(&s->open_sem);
+ drain_dac(state, file->f_flags & O_NONBLOCK);
+
+ /* stop DMA state machine and free DMA buffers */
+ down(&state->open_sem);
if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
+ stop_dac(state);
+ dealloc_dmabuf(&state->dma_dac);
}
if (file->f_mode & FMODE_READ) {
- stop_adc(s);
+ stop_adc(state);
+ dealloc_dmabuf(&state->dma_adc);
}
-
- /* free our shared dma buffers */
- dealloc_dmabuf(&s->dma_adc);
- dealloc_dmabuf(&s->dma_dac);
-
- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+ state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
/* we're covered by the open_sem */
- up(&s->open_sem);
- wake_up(&s->open_wait);
+ up(&state->open_sem);
+
+ wake_up(&state->open_wait);
+
//FIXME put back in
//MOD_DEC_USE_COUNT;
return 0;
@@ -2726,31 +2781,31 @@
&trident_llseek,
&trident_read,
&trident_write,
- NULL, /* readdir */
+ NULL, /* readdir */
&trident_poll,
&trident_ioctl,
NULL, /* XXX &trident_mmap, */
&trident_open,
NULL, /* flush */
&trident_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* check_media_change */
- NULL, /* revalidate */
- NULL, /* lock */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL, /* lock */
};
#ifdef CONFIG_APM
int trident_apm_callback(apm_event_t ae) {
+ return 0;
}
#endif
/* --------------------------------------------------------------------- */
-static int trident_install(struct pci_dev *pcidev, int card_type)
+static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
{
u16 w;
- u32 l;
unsigned long iobase;
int i;
struct trident_card *card;
@@ -2760,16 +2815,16 @@
iobase = pcidev->resource[0].start;
- if(check_region(iobase, 256))
- {
- M_printk(KERN_WARNING "(trident) can't allocate 256 bytes I/O at 0x%4.4lx\n", iobase);
+ if(check_region(iobase, 256)) {
+ printk(KERN_WARNING "trident: can't allocate I/O space at 0x%4.4lx\n",
+ iobase);
return 0;
}
/* this was tripping up some machines */
- if(pcidev->irq == 0)
- {
- printk(KERN_WARNING "(trident) pci subsystem reports irq 0, this might not be correct.\n");
+ if (pcidev->irq == 0) {
+ printk(KERN_WARNING "trident: pci subsystem reports irq 0,"
+ " this might not be correct.\n");
}
/* just to be sure */
@@ -2778,79 +2833,62 @@
pci_read_config_word(pcidev, PCI_COMMAND, &w);
if((w&(PCI_COMMAND_IO|PCI_COMMAND_MASTER)) != (PCI_COMMAND_IO|PCI_COMMAND_MASTER))
{
- printk("(trident) BIOS did not enable I/O access.\n");
+ printk(KERN_WARNING "trident: BIOS did not enable I/O access.\n");
w|=PCI_COMMAND_IO|PCI_COMMAND_MASTER;
- pci_write_config_word(pcidev, PCI_COMMAND,w);
+ pci_write_config_word(pcidev, PCI_COMMAND, w);
}
-
+
card = kmalloc(sizeof(struct trident_card), GFP_KERNEL);
- if(card == NULL)
- {
- printk(KERN_WARNING "(trident) out of memory\n");
+ if (card == NULL) {
+ printk(KERN_WARNING "trident: out of memory\n");
return 0;
}
memset(card, 0, sizeof(*card));
#ifdef CONFIG_APM
- printk("(trident) apm_reg_callback: %d\n",apm_register_callback(trident_apm_callback));
+ printk("trident: apm_reg_callback: %d\n",
+ apm_register_callback(trident_apm_callback));
#endif
card->iobase = iobase;
- card->card_type = card_type;
+ card->pci_info = pci_info;
+ card->pci_id = pci_info->device;
card->irq = pcidev->irq;
card->next = devs;
card->magic = TRIDENT_CARD_MAGIC;
devs = card;
ChanDwordCount = card->ChanDwordCount = 2;
- card->ChanPCM = 32;
card->ChRegs.lpChStart = card->ChRegs.data;
card->ChRegs.lpChStop = card->ChRegs.lpChStart + ChanDwordCount;
card->ChRegs.lpChAint = card->ChRegs.lpChStop + ChanDwordCount;
card->ChRegs.lpChAinten = card->ChRegs.lpChAint + ChanDwordCount;
+
card->ChRegs.lpAChStart = card->ChRegs.lpChAinten + ChanDwordCount;
card->ChRegs.lpAChStop = card->ChRegs.lpAChStart + ChanDwordCount;
card->ChRegs.lpAChAint = card->ChRegs.lpAChStop + ChanDwordCount;
card->ChRegs.lpAChAinten = card->ChRegs.lpAChAint + ChanDwordCount;
- // Assign addresses.
+
+ // Assign Bank A addresses.
card->ChRegs.lpAChStart[0] = T4D_START_A;
card->ChRegs.lpAChStop[0] = T4D_STOP_A;
card->ChRegs.lpAChAint[0] = T4D_AINT_A;
card->ChRegs.lpAChAinten[0] = T4D_AINTEN_A;
-
-
+ /* Assign Bank B addresses */
card->ChRegs.lpAChStart[1] = T4D_START_B;
card->ChRegs.lpAChStop[1] = T4D_STOP_B;
card->ChRegs.lpAChAint[1] = T4D_AINT_B;
card->ChRegs.lpAChAinten[1] = T4D_AINTEN_B;
-
outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
- trident_ac97_set(card, 0x0L , 0L);
- trident_ac97_set(card, 0x02L , 0L);
- trident_ac97_set(card, 0x18L , 0L);
+
- if(card->card_type == TYPE_4DWAVE_NX)
- {
- // Enable rear channels
- outl(0x12, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
- // ...or not, since they sound ugly. :)
- // outl(0x02, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
- // S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled
- // outl(0x200004, TRID_REG(card, NX_SPCSTATUS));
- // Disable S/PDIF out, 48khz only from ac97 fifo
- // outb(0x00, TRID_REG(card, NX_SPCTRL_SPCSO + 3));
- }
- else
- {
- outl(0x02, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- }
-
- for(i=0;i<NR_DSPS;i++)
- {
+ spin_lock_init(&card->lock);
+
+ for (i = 0; i < NR_DSPS; i++) {
struct trident_state *s=&card->channels[i];
s->card = card;
@@ -2859,99 +2897,80 @@
init_waitqueue_head(&s->open_wait);
init_MUTEX(&s->open_sem);
s->magic = TRIDENT_STATE_MAGIC;
- s->channel = i;
+ s->channel = i;
if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
- printk("(trident) BOTCH!\n");
-
+ printk(KERN_ERR "trident: BOTCH!\n");
+
/*
* Now allocate the hardware resources
*/
-
+
//s->dma_dac.chan[0] = AllocateChannelPCM(card);
- s->dma_dac.chan[1] = AllocateChannelPCM(card);
//s->dma_adc.chan[0] = AllocateChannelPCM(card);
-
+ s->dma_dac.chan[1] = trident_alloc_pcm_channel(card);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0)
break;
}
-
+
num = i;
-
+
/* clear the rest if we ran out of slots to register */
- for(;i<NR_DSPS;i++)
- {
+ for (;i < NR_DSPS; i++){
struct trident_state *s=&card->channels[i];
s->dev_audio = -1;
}
-
+
trident = &card->channels[0];
/*
* Ok card ready. Begin setup proper
*/
- printk(KERN_INFO "(trident) Configuring %s found at IO 0x%04lX IRQ %d\n",
- card_names[card_type],card->iobase,card->irq);
+ printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
+ card->pci_info->name, card->iobase, card->irq);
/* stake our claim on the iospace */
- request_region(iobase, 256, card_names[card_type]);
-
- /*
- * Reset the CODEC
- */
-
+ request_region(iobase, 256, card->pci_info->name);
+
trident_ac97_init(card);
- if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0)
- {
- printk("(trident) couldn't register mixer!\n");
+ if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "trident: couldn't register mixer!\n");
}
- else
- {
+ else {
int i;
- for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)
- {
+ for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
struct mixer_defaults *md = &mixer_defaults[i];
- if(md->mixer == -1)
+ if (md->mixer == -1)
break;
- if(!supported_mixer(card,md->mixer))
+ if (!supported_mixer(card, md->mixer))
continue;
- set_mixer(card,md->mixer,md->value);
+ set_mixer(card, md->mixer, md->value);
}
}
-
- if(request_irq(card->irq, trident_interrupt, SA_SHIRQ, card_names[card_type], card))
- {
- printk(KERN_ERR "(trident) unable to allocate irq %d,\n", card->irq);
+
+ if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) {
+ printk(KERN_ERR "trident: unable to allocate irq %d,\n", card->irq);
unregister_sound_mixer(card->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
+ for (i = 0; i < NR_DSPS; i++) {
struct trident_state *s = &card->channels[i];
if(s->dev_audio != -1)
unregister_sound_dsp(s->dev_audio);
}
- release_region(card->iobase, 256);
+ release_region(card->iobase, 256);
kfree(card);
return 0;
}
- init_timer(&debug_timer);
- debug_timer.function = trident_kick;
- debug_timer.data = (unsigned long)card;
- debug_timer.expires = jiffies+1;
-
-// add_timer(&debug_timer);
-
- printk("(trident) %d channels configured.\n", num);
-
- EnableEndInterrupts(card);
+ trident_enable_end_interrupts(card);
return 1;
}
+
#ifdef MODULE
int init_module(void)
#else
@@ -2960,34 +2979,24 @@
{
struct pci_dev *pcidev = NULL;
int foundone = 0;
+ int i;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "(trident) version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n");
-
- pcidev = NULL;
- /*
- * Find the 4DWave DX
- */
-
- while( (pcidev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, pcidev))!=NULL
- &&
- ( trident_install(pcidev, TYPE_4DWAVE_DX) )) {
- foundone=1;
- }
-
- /*
- * Find the 4DWave NX
- */
+ printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
+ DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
- while((pcidev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, pcidev))!=NULL
- &&
- ( trident_install(pcidev, TYPE_4DWAVE_NX) )) {
- foundone=1;
+ for (i = 0; i < sizeof (pci_audio_devices); i++) {
+ pcidev = NULL;
+ while ((pcidev = pci_find_device(pci_audio_devices[i].vendor,
+ pci_audio_devices[i].device,
+ pcidev)) != NULL) {
+ foundone += trident_install(pcidev, pci_audio_devices + i);
+ }
}
- if( ! foundone )
+ if (!foundone)
return -ENODEV;
return 0;
}
@@ -2997,44 +3006,33 @@
#ifdef MODULE
MODULE_AUTHOR("Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("Trident 4DWave Driver");
-#ifdef M_DEBUG
+MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
+#ifdef DEBUG
MODULE_PARM(debug,"i");
#endif
void cleanup_module(void)
{
- struct trident_card *s;
-
#ifdef CONFIG_APM
apm_unregister_callback(trident_apm_callback);
#endif
- del_timer(&debug_timer);
-
- while ((s = devs)) {
+ while (devs != NULL) {
int i;
- devs = devs->next;
-
-
+
/* Kill interrupts, and SP/DIF */
-
- DisableEndInterrupts(s);
- if(s->card_type == TYPE_4DWAVE_NX)
- outb(0x00, TRID_REG(s, NX_SPCTRL_SPCSO+3));
-
- free_irq(s->irq, s);
- unregister_sound_mixer(s->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
- struct trident_state *trident = &s->channels[i];
- if(trident->dev_audio != -1)
+ trident_disable_end_interrupts(devs);
+ free_irq(devs->irq, devs);
+ unregister_sound_mixer(devs->dev_mixer);
+ for (i = 0; i < NR_DSPS; i++) {
+ struct trident_state *trident = &devs->channels[i];
+ if (trident->dev_audio != -1)
unregister_sound_dsp(trident->dev_audio);
}
- release_region(s->iobase, 256);
- kfree(s);
+ release_region(devs->iobase, 256);
+ kfree(devs);
+ devs = devs->next;
}
- printk("(trident) unloading\n");
}
#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)