patch-2.3.15 linux/drivers/sound/es1371.c
Next file: linux/drivers/sound/mad16.c
Previous file: linux/drivers/sound/es1370.c
Back to the patch index
Back to the overall index
- Lines: 859
- Date:
Mon Aug 23 11:15:27 1999
- Orig file:
v2.3.14/linux/drivers/sound/es1371.c
- Orig date:
Thu Aug 12 12:21:48 1999
diff -u --recursive --new-file v2.3.14/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
@@ -74,6 +74,13 @@
* 10.08.99 0.15 (Re)added S/PDIF module option for cards revision >= 4.
* Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
* module_init/__setup fixes
+ * 08.16.99 0.16 Joe Cotellese <joec@ensoniq.com>
+ * Added detection for ES1371 revision ID so that we can
+ * detect the ES1373 and later parts.
+ * added AC97 #defines for readability
+ * added a /proc file system for dumping hardware state
+ * updated SRC and CODEC w/r functions to accomodate bugs
+ * in some versions of the ES137x chips.
*
*/
@@ -89,17 +96,21 @@
#include <linux/malloc.h>
#include <linux/soundcard.h>
#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
#include <linux/init.h>
#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include <asm/dma.h>
#include <asm/spinlock.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
+#include "ac97.h"
/* --------------------------------------------------------------------- */
#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+#define ES1371_DEBUG
/* --------------------------------------------------------------------- */
@@ -110,6 +121,18 @@
#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
#endif
+/* ES1371 chip ID */
+/* This is a little confusing because all ES1371 compatible chips have the
+ same DEVICE_ID, the only thing differentiating them is the REV_ID field.
+ This is only significant if you want to enable features on the later parts.
+ Yes, I know it's stupid and why didn't we use the sub IDs?
+*/
+#define ES1371REV_ES1373_A 0x04
+#define ES1371REV_ES1373_B 0x06
+#define ES1371REV_CT5880_A 0x07
+#define ES1371REV_ES1371_B 0x09
+
+
#define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371)
#define ES1371_EXTENT 0x40
@@ -209,14 +232,22 @@
#define UCTRL_CNTRL_SWR 0x03 /* software reset command */
/* sample rate converter */
+#define SRC_OKSTATE 1
+
#define SRC_RAMADDR_MASK 0xfe000000
#define SRC_RAMADDR_SHIFT 25
+#define SRC_DAC1FREEZE (1UL << 21)
+#define SRC_DAC2FREEZE (1UL << 20)
+#define SRC_ADCFREEZE (1UL << 19)
+
+
#define SRC_WE 0x01000000 /* read/write control for SRC RAM */
#define SRC_BUSY 0x00800000 /* SRC busy */
#define SRC_DIS 0x00400000 /* 1 = disable SRC */
#define SRC_DDAC1 0x00200000 /* 1 = disable accum update for DAC1 */
#define SRC_DDAC2 0x00100000 /* 1 = disable accum update for DAC2 */
#define SRC_DADC 0x00080000 /* 1 = disable accum update for ADC2 */
+#define SRC_CTLMASK 0x00780000
#define SRC_RAMDATA_MASK 0x0000ffff
#define SRC_RAMDATA_SHIFT 0
@@ -296,7 +327,7 @@
/* misc stuff */
-
+#define POLL_COUNT 0x1000
#define FMODE_DAC 4 /* slight misuse of mode_t */
/* MIDI buffer sizes */
@@ -355,8 +386,13 @@
/* hardware resources */
unsigned long io; /* long for SPARC */
unsigned int irq;
-
- /* mixer registers; there is no HW readback */
+ u8 rev; /* the chip revision */
+
+#ifdef ES1371_DEBUG
+ /* debug /proc entry */
+ struct proc_dir_entry *ps;
+#endif /* ES1371_DEBUG */
+ /* mixer registers; there is no HW readback */
struct {
unsigned short codec_id;
unsigned int modcnt;
@@ -441,31 +477,12 @@
}
/* --------------------------------------------------------------------- */
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-extern __inline__ unsigned int hweight32(unsigned int w)
-{
- unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
- res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
- res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
- res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
- return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
-/* --------------------------------------------------------------------- */
static unsigned wait_src_ready(struct es1371_state *s)
{
unsigned int t, r;
- for (t = 0; t < 1000; t++) {
+ for (t = 0; t < POLL_COUNT; t++) {
if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY))
return r;
udelay(1);
@@ -476,29 +493,53 @@
static unsigned src_read(struct es1371_state *s, unsigned reg)
{
- unsigned int r;
+ unsigned int temp,i,orig;
- r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
- r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
- outl(r, s->io + ES1371_REG_SRCONV);
- return (wait_src_ready(s) & SRC_RAMDATA_MASK) >> SRC_RAMDATA_SHIFT;
-}
+ /* wait for ready */
+ temp = wait_src_ready (s);
+ /* we can only access the SRC at certain times, make sure
+ we're allowed to before we read */
+
+ orig = temp;
+ /* expose the SRC state bits */
+ outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL,
+ s->io + ES1371_REG_SRCONV);
+
+ /* now, wait for busy and the correct time to read */
+ temp = wait_src_ready (s);
+
+ if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){
+ /* wait for the right state */
+ for (i=0; i<POLL_COUNT; i++){
+ temp = inl (s->io + ES1371_REG_SRCONV);
+ if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 ))
+ break;
+ }
+ }
+
+ /* hide the state bits */
+ outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV);
+ return temp;
+
+
+}
static void src_write(struct es1371_state *s, unsigned reg, unsigned data)
{
+
unsigned int r;
r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK;
outl(r | SRC_WE, s->io + ES1371_REG_SRCONV);
+
}
/* --------------------------------------------------------------------- */
/* most of the following here is black magic */
-
static void set_adc_rate(struct es1371_state *s, unsigned rate)
{
unsigned long flags;
@@ -535,6 +576,7 @@
spin_unlock_irqrestore(&s->lock, flags);
}
+
static void set_dac1_rate(struct es1371_state *s, unsigned rate)
{
unsigned long flags;
@@ -569,6 +611,7 @@
rate = 4000;
freq = (rate << 15) / 3000;
s->dac2rate = (freq * 3000) >> 15;
+ printk (KERN_DEBUG "dac2 freq: %d\n", freq);
spin_lock_irqsave(&s->lock, flags);
r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2;
outl(r, s->io + ES1371_REG_SRCONV);
@@ -583,26 +626,80 @@
/* --------------------------------------------------------------------- */
+static void __init src_init(struct es1371_state *s)
+{
+ unsigned int i;
+
+ /* before we enable or disable the SRC we need
+ to wait for it to become ready */
+ wait_src_ready(s);
+
+ outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
+
+ for (i = 0; i < 0x80; i++)
+ src_write(s, i, 0);
+
+ src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
+ src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
+ src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
+ src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
+ src_write(s, SRCREG_VOL_ADC, 1 << 12);
+ src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
+ src_write(s, SRCREG_VOL_DAC1, 1 << 12);
+ src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
+ src_write(s, SRCREG_VOL_DAC2, 1 << 12);
+ src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
+ set_adc_rate(s, 22050);
+ set_dac1_rate(s, 22050);
+ set_dac2_rate(s, 22050);
+
+ /* WARNING:
+ * enabling the sample rate converter without properly programming
+ * its parameters causes the chip to lock up (the SRC busy bit will
+ * be stuck high, and I've found no way to rectify this other than
+ * power cycle)
+ */
+ wait_src_ready(s);
+ outl(0, s->io+ES1371_REG_SRCONV);
+}
+
+/* --------------------------------------------------------------------- */
+
static void wrcodec(struct es1371_state *s, unsigned addr, unsigned data)
{
unsigned long flags;
unsigned t, x;
-
- for (t = 0; t < 0x1000; t++)
+
+ for (t = 0; t < POLL_COUNT; t++)
if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
break;
spin_lock_irqsave(&s->lock, flags);
- /* save the current state for later */
- x = inl(s->io+ES1371_REG_SRCONV);
- /* enable SRC state data in SRC mux */
- outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
+
+ /* save the current state for later */
+ x = wait_src_ready(s);
+
+ /* enable SRC state data in SRC mux */
+ outl(( x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
s->io+ES1371_REG_SRCONV);
- /* wait for a SAFE time to write addr/data and then do it, dammit */
- for (t = 0; t < 0x1000; t++)
- if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
- break;
+
+ /* wait for not busy (state 0) first to avoid
+ transition states */
+ for (t=0; t<POLL_COUNT; t++){
+ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+ break;
+ udelay(1);
+ }
+
+ /* wait for a SAFE time to write addr/data and then do it, dammit */
+ for (t=0; t<POLL_COUNT; t++){
+ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+ break;
+ udelay(1);
+ }
+
outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) |
((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC);
+
/* restore SRC reg */
wait_src_ready(s);
outl(x, s->io+ES1371_REG_SRCONV);
@@ -614,28 +711,50 @@
unsigned long flags;
unsigned t, x;
+ /* wait for WIP to go away */
for (t = 0; t < 0x1000; t++)
if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
break;
spin_lock_irqsave(&s->lock, flags);
+
/* save the current state for later */
- x = inl(s->io+ES1371_REG_SRCONV);
+ x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC));
+
/* enable SRC state data in SRC mux */
- outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
- s->io+ES1371_REG_SRCONV);
- /* wait for a SAFE time to write addr/data and then do it, dammit */
- for (t = 0; t < 0x1000; t++)
- if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
- break;
+ outl( x | 0x00010000,
+ s->io+ES1371_REG_SRCONV);
+
+ /* wait for not busy (state 0) first to avoid
+ transition states */
+ for (t=0; t<POLL_COUNT; t++){
+ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+ break;
+ udelay(1);
+ }
+
+ /* wait for a SAFE time to write addr/data and then do it, dammit */
+ for (t=0; t<POLL_COUNT; t++){
+ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+ break;
+ udelay(1);
+ }
+
outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC);
/* restore SRC reg */
wait_src_ready(s);
outl(x, s->io+ES1371_REG_SRCONV);
spin_unlock_irqrestore(&s->lock, flags);
- /* now wait for the stinkin' data (RDY) */
+
+ /* wait for WIP again */
for (t = 0; t < 0x1000; t++)
+ if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
+ break;
+
+ /* now wait for the stinkin' data (RDY) */
+ for (t = 0; t < POLL_COUNT; t++)
if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY)
break;
+
return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT);
}
@@ -996,6 +1115,21 @@
/* --------------------------------------------------------------------- */
+/*
+ * AC97 Mixer Register to Connections mapping of the Concert 97 board
+ *
+ * AC97_MASTER_VOL_STEREO Line Out
+ * AC97_MASTER_VOL_MONO TAD Output
+ * AC97_PCBEEP_VOL none
+ * AC97_PHONE_VOL TAD Input (mono)
+ * AC97_MIC_VOL MIC Input (mono)
+ * AC97_LINEIN_VOL Line Input (stereo)
+ * AC97_CD_VOL CD Input (stereo)
+ * AC97_VIDEO_VOL none
+ * AC97_AUX_VOL Aux Input (stereo)
+ * AC97_PCMOUT_VOL Wave Output (stereo)
+ */
+
#define AC97_PESSIMISTIC
/*
@@ -1021,25 +1155,25 @@
static const unsigned char volreg[SOUND_MIXER_NRDEVICES] =
{
/* 5 bit stereo */
- [SOUND_MIXER_LINE] = 0x10,
- [SOUND_MIXER_CD] = 0x12,
- [SOUND_MIXER_VIDEO] = 0x14,
- [SOUND_MIXER_LINE1] = 0x16,
- [SOUND_MIXER_PCM] = 0x18,
+ [SOUND_MIXER_LINE] = AC97_LINEIN_VOL,
+ [SOUND_MIXER_CD] = AC97_CD_VOL,
+ [SOUND_MIXER_VIDEO] = AC97_VIDEO_VOL,
+ [SOUND_MIXER_LINE1] = AC97_AUX_VOL,
+ [SOUND_MIXER_PCM] = AC97_PCMOUT_VOL,
/* 6 bit stereo */
- [SOUND_MIXER_VOLUME] = 0x02,
- [SOUND_MIXER_PHONEOUT] = 0x04,
+ [SOUND_MIXER_VOLUME] = AC97_MASTER_VOL_STEREO,
+ [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONE_VOL,
/* 6 bit mono */
- [SOUND_MIXER_OGAIN] = 0x06,
- [SOUND_MIXER_PHONEIN] = 0x0c,
+ [SOUND_MIXER_OGAIN] = AC97_MASTER_VOL_MONO,
+ [SOUND_MIXER_PHONEIN] = AC97_PHONE_VOL,
/* 4 bit mono but shifted by 1 */
- [SOUND_MIXER_SPEAKER] = 0x08,
+ [SOUND_MIXER_SPEAKER] = AC97_MASTER_TONE,
/* 6 bit mono + preamp */
- [SOUND_MIXER_MIC] = 0x0e,
+ [SOUND_MIXER_MIC] = AC97_MIC_VOL,
/* 4 bit stereo */
- [SOUND_MIXER_RECLEV] = 0x1c,
+ [SOUND_MIXER_RECLEV] = AC97_RECORD_GAIN,
/* 4 bit mono */
- [SOUND_MIXER_IGAIN] = 0x1e
+ [SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC
};
#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -1052,8 +1186,8 @@
switch (ch) {
case SOUND_MIXER_MIC:
- j = rdcodec(s, 0x0e);
- if (j & 0x8000)
+ j = rdcodec(s, AC97_MIC_VOL);
+ if (j & AC97_MUTE)
return put_user(0, (int *)arg);
#ifdef AC97_PESSIMISTIC
return put_user(0x4949 - 0x202 * (j & 0x1f) + ((j & 0x40) ? 0x1b1b : 0), (int *)arg);
@@ -1064,7 +1198,7 @@
case SOUND_MIXER_OGAIN:
case SOUND_MIXER_PHONEIN:
j = rdcodec(s, volreg[ch]);
- if (j & 0x8000)
+ if (j & AC97_MUTE)
return put_user(0, (int *)arg);
#ifdef AC97_PESSIMISTIC
return put_user(0x6464 - 0x303 * (j & 0x1f), (int *)arg);
@@ -1078,7 +1212,7 @@
/* fall through */
case SOUND_MIXER_VOLUME:
j = rdcodec(s, volreg[ch]);
- if (j & 0x8000)
+ if (j & AC97_MUTE)
return put_user(0, (int *)arg);
#ifdef AC97_PESSIMISTIC
return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
@@ -1087,8 +1221,8 @@
#endif /* AC97_PESSIMISTIC */
case SOUND_MIXER_SPEAKER:
- j = rdcodec(s, 0x0a);
- if (j & 0x8000)
+ j = rdcodec(s, AC97_PCBEEP_VOL);
+ if (j & AC97_MUTE
return put_user(0, (int *)arg);
return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg);
@@ -1098,7 +1232,7 @@
case SOUND_MIXER_LINE1:
case SOUND_MIXER_PCM:
j = rdcodec(s, volreg[ch]);
- if (j & 0x8000)
+ if (j & AC97_MUTE)
return put_user(0, (int *)arg);
return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
@@ -1106,23 +1240,23 @@
case SOUND_MIXER_TREBLE:
if (!(s->mix.codec_id & CODEC_ID_BASSTREBLE))
return -EINVAL;
- j = rdcodec(s, 0x08);
+ j = rdcodec(s, AC97_MASTER_TONE);
if (ch == SOUND_MIXER_BASS)
j >>= 8;
return put_user((((j & 15) * 100) / 15) * 0x101, (int *)arg);
/* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
case SOUND_MIXER_RECLEV:
- j = rdcodec(s, 0x1c);
- if (j & 0x8000)
+ j = rdcodec(s, AC97_RECORD_GAIN);
+ if (j & AC97_MUTE)
return put_user(0, (int *)arg);
return put_user((swab(j) & 0xf0f) * 6 + 0xa0a, (int *)arg);
case SOUND_MIXER_IGAIN:
if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
return -EINVAL;
- j = rdcodec(s, 0x1e);
- if (j & 0x8000)
+ j = rdcodec(s, AC97_RECORD_GAIN_MIC);
+ if (j & AC97_MUTE)
return put_user(0, (int *)arg);
return put_user((j & 0xf) * 0x606 + 0xa0a, (int *)arg);
@@ -1177,7 +1311,7 @@
case SOUND_MIXER_LINE1:
case SOUND_MIXER_PCM:
if (l1 < 7 && r1 < 7) {
- wrcodec(s, volreg[ch], 0x8000);
+ wrcodec(s, volreg[ch], AC97_MUTE);
return 0;
}
if (l1 < 7)
@@ -1194,7 +1328,7 @@
case SOUND_MIXER_VOLUME:
#ifdef AC97_PESSIMISTIC
if (l1 < 7 && r1 < 7) {
- wrcodec(s, volreg[ch], 0x8000);
+ wrcodec(s, volreg[ch], AC97_MUTE);
return 0;
}
if (l1 < 7)
@@ -1205,7 +1339,7 @@
return 0;
#else /* AC97_PESSIMISTIC */
if (l1 < 4 && r1 < 4) {
- wrcodec(s, volreg[ch], 0x8000);
+ wrcodec(s, volreg[ch], AC97_MUTE);
return 0;
}
if (l1 < 4)
@@ -1219,21 +1353,21 @@
case SOUND_MIXER_OGAIN:
case SOUND_MIXER_PHONEIN:
#ifdef AC97_PESSIMISTIC
- wrcodec(s, volreg[ch], (l1 < 7) ? 0x8000 : (100 - l1) / 3);
+ wrcodec(s, volreg[ch], (l1 < 7) ? AC97_MUTE : (100 - l1) / 3);
return 0;
#else /* AC97_PESSIMISTIC */
- wrcodec(s, volreg[ch], (l1 < 4) ? 0x8000 : (2 * (100 - l1) / 3));
+ wrcodec(s, volreg[ch], (l1 < 4) ? AC97_MUTE : (2 * (100 - l1) / 3));
return 0;
#endif /* AC97_PESSIMISTIC */
case SOUND_MIXER_SPEAKER:
- wrcodec(s, 0x0a, (l1 < 10) ? 0x8000 : ((100 - l1) / 6) << 1);
+ wrcodec(s, AC97_PCBEEP_VOL, (l1 < 10) ? AC97_MUTE : ((100 - l1) / 6) << 1);
return 0;
case SOUND_MIXER_MIC:
#ifdef AC97_PESSIMISTIC
if (l1 < 11) {
- wrcodec(s, 0x0e, 0x8000);
+ wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
return 0;
}
i = 0;
@@ -1243,11 +1377,11 @@
}
if (l1 < 11)
l1 = 11;
- wrcodec(s, 0x0e, ((73 - l1) / 2) | i);
+ wrcodec(s, AC97_MIC_VOL, ((73 - l1) / 2) | i);
return 0;
#else /* AC97_PESSIMISTIC */
if (l1 < 9) {
- wrcodec(s, 0x0e, 0x8000);
+ wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
return 0;
}
i = 0;
@@ -1257,37 +1391,37 @@
}
if (l1 < 9)
l1 = 9;
- wrcodec(s, 0x0e, (((87 - l1) * 4) / 5) | i);
+ wrcodec(s, AC97_MIC_VOL, (((87 - l1) * 4) / 5) | i);
return 0;
#endif /* AC97_PESSIMISTIC */
case SOUND_MIXER_BASS:
val = ((l1 * 15) / 100) & 0xf;
- wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0x00ff) | (val << 8));
+ wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0x00ff) | (val << 8));
return 0;
case SOUND_MIXER_TREBLE:
val = ((l1 * 15) / 100) & 0xf;
- wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0xff00) | val);
+ wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0xff00) | val);
return 0;
/* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
case SOUND_MIXER_RECLEV:
if (l1 < 10 || r1 < 10) {
- wrcodec(s, 0x1c, 0x8000);
+ wrcodec(s, AC97_RECORD_GAIN, AC97_MUTE);
return 0;
}
if (l1 < 10)
l1 = 10;
if (r1 < 10)
r1 = 10;
- wrcodec(s, 0x1c, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
+ wrcodec(s, AC97_RECORD_GAIN, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
return 0;
case SOUND_MIXER_IGAIN:
if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
return -EINVAL;
- wrcodec(s, 0x1e, (l1 < 10) ? 0x8000 : ((l1 - 10) / 6) & 0xf);
+ wrcodec(s, AC97_RECORD_GAIN_MIC, (l1 < 10) ? AC97_MUTE : ((l1 - 10) / 6) & 0xf);
return 0;
default:
@@ -1305,8 +1439,8 @@
return -EINVAL;
get_user_ret(val, (int *)arg, -EFAULT);
if (val & 1)
- wrcodec(s, 0x22, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
- val = rdcodec(s, 0x22);
+ wrcodec(s, AC97_3D_CONTROL, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
+ val = rdcodec(s, AC97_3D_CONTROL);
return put_user(((val & 0xf) << 1) | ((val & 0xf00) >> 3), (int *)arg);
}
if (cmd == SOUND_MIXER_INFO) {
@@ -1333,7 +1467,7 @@
if (_IOC_DIR(cmd) == _IOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(recsrc[rdcodec(s, 0x1a) & 7], (int *)arg);
+ return put_user(recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7], (int *)arg);
case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO |
@@ -1380,10 +1514,10 @@
if (i == 0)
return 0; /*val = mixer_recmask(s);*/
else if (i > 1)
- val &= ~recsrc[rdcodec(s, 0x1a) & 7];
+ val &= ~recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7];
for (i = 0; i < 8; i++) {
if (val & recsrc[i]) {
- wrcodec(s, 0x1a, 0x101 * i);
+ wrcodec(s, AC97_RECORD_SELECT, 0x101 * i);
return 0;
}
}
@@ -1473,8 +1607,9 @@
if (s->dma_dac1.mapped || !s->dma_dac1.ready)
return 0;
- current->state = TASK_INTERRUPTIBLE;
+
add_wait_queue(&s->dma_dac1.wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
for (;;) {
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac1.count;
@@ -1491,7 +1626,7 @@
tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "es1371: dma timed out??\n");
+ printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
}
remove_wait_queue(&s->dma_dac1.wait, &wait);
current->state = TASK_RUNNING;
@@ -1508,8 +1643,9 @@
if (s->dma_dac2.mapped || !s->dma_dac2.ready)
return 0;
- current->state = TASK_INTERRUPTIBLE;
+
add_wait_queue(&s->dma_dac2.wait, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
for (;;) {
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac2.count;
@@ -1526,7 +1662,7 @@
tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "es1371: dma timed out??\n");
+ printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
}
remove_wait_queue(&s->dma_dac2.wait, &wait);
current->state = TASK_RUNNING;
@@ -1753,6 +1889,7 @@
if (file->f_mode & FMODE_WRITE) {
stop_dac2(s);
s->dma_dac2.ready = 0;
+ printk (KERN_DEBUG "es137x: setting DAC2 rate: %d\n", val);
set_dac2_rate(s, val);
}
}
@@ -2700,6 +2837,44 @@
/* --------------------------------------------------------------------- */
+/*
+ * for debugging purposes, we'll create a proc device that dumps the
+ * CODEC chipstate
+ */
+
+#ifdef ES1371_DEBUG
+static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+{
+ int len = 0;
+
+ struct es1371_state *s = devs;
+ int cnt;
+
+ /* print out header */
+ len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n");
+
+ /* print out CODEC state */
+ len += sprintf (buf + len, "AC97 CODEC state\n");
+
+ for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
+ len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(s , cnt));
+
+ if (fpos >=len){
+ *start = buf;
+ *eof =1;
+ return 0;
+ }
+ *start = buf + fpos;
+ if ((len -= fpos) > length)
+ return length;
+ *eof =1;
+ return len;
+
+}
+#endif /* ES1371_DEBUG */
+
+/* --------------------------------------------------------------------- */
+
/* maximum number of devices */
#define NR_DEVICE 5
@@ -2741,7 +2916,6 @@
struct pci_dev *pcidev = NULL;
mm_segment_t fs;
int i, val, val2, index = 0;
- u8 revision;
unsigned cssr;
if (!pci_present()) /* No PCI bus in this machine! */
@@ -2769,6 +2943,7 @@
s->magic = ES1371_MAGIC;
s->io = pcidev->resource[0].start;
s->irq = pcidev->irq;
+ pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
if (check_region(s->io, ES1371_EXTENT)) {
printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
goto err_region;
@@ -2778,8 +2953,8 @@
printk(KERN_ERR "es1371: irq %u in use\n", s->irq);
goto err_irq;
}
- printk(KERN_INFO "es1371: found adapter at io %#lx irq %u\n"
- KERN_INFO "es1371: features: joystick 0x%x\n", s->io, s->irq, joystick[index]);
+ printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n"
+ KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0)
goto err_dev1;
@@ -2789,6 +2964,13 @@
goto err_dev3;
if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0)
goto err_dev4;
+#ifdef ES1371_DEBUG
+ /* intialize the debug proc device */
+ s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL);
+ if (s->ps)
+ s->ps->read_proc = proc_es1371_dump;
+#endif /* ES1371_DEBUG */
+
/* initialize codec registers */
s->ctrl = 0;
if ((joystick[index] & ~0x18) == 0x200) {
@@ -2801,14 +2983,13 @@
s->sctrl = 0;
cssr = 0;
/* check to see if s/pdif mode is being requested */
- pci_read_config_byte(pcidev, PCI_REVISION_ID, &revision);
if (spdif[index]) {
- if (revision >= 4) {
+ if (s->rev >= 4) {
printk(KERN_INFO "es1371: enabling S/PDIF output\n");
cssr |= STAT_EN_SPDIF;
s->ctrl |= CTRL_SPDIFEN_B;
} else {
- printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", revision);
+ printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
}
}
/* initialize the chips */
@@ -2821,35 +3002,12 @@
udelay(2);
outl(s->ctrl, s->io+ES1371_REG_CONTROL);
/* init the sample rate converter */
- outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
- for (val = 0; val < 0x80; val++)
- src_write(s, val, 0);
- src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
- src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
- src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
- src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
- src_write(s, SRCREG_VOL_ADC, 1 << 12);
- src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
- src_write(s, SRCREG_VOL_DAC1, 1 << 12);
- src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
- src_write(s, SRCREG_VOL_DAC2, 1 << 12);
- src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
- set_adc_rate(s, 22050);
- set_dac1_rate(s, 22050);
- set_dac2_rate(s, 22050);
- /* WARNING:
- * enabling the sample rate converter without properly programming
- * its parameters causes the chip to lock up (the SRC busy bit will
- * be stuck high, and I've found no way to rectify this other than
- * power cycle)
- */
- wait_src_ready(s);
- outl(0, s->io+ES1371_REG_SRCONV);
+ src_init(s);
/* codec init */
- wrcodec(s, 0x00, 0); /* reset codec */
- s->mix.codec_id = rdcodec(s, 0x00); /* get codec ID */
- val = rdcodec(s, 0x7c);
- val2 = rdcodec(s, 0x7e);
+ wrcodec(s, AC97_RESET, 0); /* reset codec */
+ s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */
+ val = rdcodec(s, AC97_VENDOR_ID1);
+ val2 = rdcodec(s, AC97_VENDOR_ID2);
printk(KERN_INFO "es1371: codec vendor %c%c%c revision %d\n",
(val >> 8) & 0xff, val & 0xff, (val2 >> 8) & 0xff, val2 & 0xff);
printk(KERN_INFO "es1371: codec features");
@@ -2876,6 +3034,7 @@
printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none");
val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK;
printk(KERN_INFO "es1371: stereo enhancement: %s\n", (val <= 20) ? stereo_enhancement[val] : "unknown");
+
fs = get_fs();
set_fs(KERNEL_DS);
val = SOUND_MASK_LINE;
@@ -2918,6 +3077,10 @@
while ((s = devs)) {
devs = devs->next;
+#ifdef ES1371_DEBUG
+ if (s->ps)
+ remove_proc_entry("es1371", NULL);
+#endif /* ES1371_DEBUG */
outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
synchronize_irq();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)