summaryrefslogtreecommitdiffstats
path: root/drivers/sound/sb_ess.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
commit0ae8dceaebe3659ee0c3352c08125f403e77ebca (patch)
tree5085c389f09da78182b899d19fe1068b619a69dd /drivers/sound/sb_ess.c
parent273767781288c35c9d679e908672b9996cda4c34 (diff)
Merge with 2.3.10.
Diffstat (limited to 'drivers/sound/sb_ess.c')
-rw-r--r--drivers/sound/sb_ess.c1031
1 files changed, 613 insertions, 418 deletions
diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c
index 3f55b74cf..c43ebf130 100644
--- a/drivers/sound/sb_ess.c
+++ b/drivers/sound/sb_ess.c
@@ -40,10 +40,10 @@
* recording problems for high samplerates. I
* fixed this by removing ess_calc_best_speed ()
* and just doing what the documentation says.
- *Javier Achirica(May 15 1999): Major cleanup, MPU IRQ sharing, hardware
- * volume support, PNP chip configuration,
- * full duplex in most cards, sample rate fine
- * tuning.
+ * Andy Sloane (June 4 1999): Stole some code from ALSA to fix the playback
+ * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888.
+ * 1879's were previously ignored by this driver;
+ * added (untested) support for those.
*
* This files contains ESS chip specifics. It's based on the existing ESS
* handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This
@@ -183,7 +183,6 @@
* ES1946 yes This is a PCI chip; not handled by this driver
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include "sound_config.h"
@@ -195,29 +194,22 @@
#define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */
#define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */
-int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */
+int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */
-#define SUBMDL_ES688 0x00 /* Subtype ES688 for specific handling */
-#define SUBMDL_ES1688 0x08 /* Subtype ES1688 for specific handling */
#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */
#define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */
#define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */
#define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */
-#define SUBMDL_ES1879 0x14 /* Subtype ES1879 for specific handling */
-#define SUBMDL_ES1887 0x15 /* Subtype ES1887 for specific handling */
-#define SUBMDL_ES1888 0x16 /* Subtype ES1888 for specific handling */
-
- /* Recording mixer, stereo full duplex */
-#define ESSCAP_NEW 0x00000100
- /* ISA PnP configuration */
-#define ESSCAP_PNP 0x00000200
- /* Full duplex, 6-bit volume, hardware volume controls */
-#define ESSCAP_ES18 0x00000400
- /* New interrupt handling system (ESS 1887) */
-#define ESSCAP_IRQ 0x00000800
-
-#define ESSFMT_16 0x00000001
-#define ESSFMT_SIGNED 0x00000004
+#define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */
+#define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */
+#define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */
+
+#define SB_CAP_ES18XX_RATE 0x100
+
+#define ES1688_CLOCK1 795444 /* 128 - div */
+#define ES1688_CLOCK2 397722 /* 256 - div */
+#define ES18XX_CLOCK1 793800 /* 128 - div */
+#define ES18XX_CLOCK2 768000 /* 256 - div */
#ifdef FKS_LOGGING
static void ess_show_mixerregs (sb_devc *devc);
@@ -233,6 +225,52 @@ static void ess_chgmixer
* *
****************************************************************************/
+struct ess_command {short cmd; short data;};
+
+/*
+ * Commands for initializing Audio 1 for input (record)
+ */
+static struct ess_command ess_i08m[] = /* input 8 bit mono */
+ { {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };
+static struct ess_command ess_i16m[] = /* input 16 bit mono */
+ { {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };
+static struct ess_command ess_i08s[] = /* input 8 bit stereo */
+ { {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };
+static struct ess_command ess_i16s[] = /* input 16 bit stereo */
+ { {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };
+
+static struct ess_command *ess_inp_cmds[] =
+ { ess_i08m, ess_i16m, ess_i08s, ess_i16s };
+
+
+/*
+ * Commands for initializing Audio 1 for output (playback)
+ */
+static struct ess_command ess_o08m[] = /* output 8 bit mono */
+ { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };
+static struct ess_command ess_o16m[] = /* output 16 bit mono */
+ { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };
+static struct ess_command ess_o08s[] = /* output 8 bit stereo */
+ { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };
+static struct ess_command ess_o16s[] = /* output 16 bit stereo */
+ { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };
+
+static struct ess_command *ess_out_cmds[] =
+ { ess_o08m, ess_o16m, ess_o08s, ess_o16s };
+
+static void ess_exec_commands
+ (sb_devc *devc, struct ess_command *cmdtab[])
+{
+ struct ess_command *cmd;
+
+ cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ];
+
+ while (cmd->cmd != -1) {
+ ess_write (devc, cmd->cmd, cmd->data);
+ cmd++;
+ }
+}
+
static void ess_change
(sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val)
{
@@ -272,21 +310,53 @@ static void ess_set_input_parms
devc->irq_mode = IMODE_INPUT;
}
-static int ess_calc_div (int clock, int *speedp, int *diffp)
+static int ess_calc_div (int clock, int revert, int *speedp, int *diffp)
{
int divider;
int speed, diff;
+ int retval;
speed = *speedp;
divider = (clock + speed / 2) / speed;
- if (divider > 127) {
- divider = 127;
+ retval = revert - divider;
+ if (retval > revert - 1) {
+ retval = revert - 1;
+ divider = revert - retval;
}
+ /* This line is suggested. Must be wrong I think
+ *speedp = (clock + divider / 2) / divider;
+ So I chose the next one */
+
*speedp = clock / divider;
diff = speed - *speedp;
- *diffp = diff < 0 ? -diff : diff;
+ if (diff < 0) diff =-diff;
+ *diffp = diff;
+
+ return retval;
+}
+
+static int ess_calc_best_speed
+ (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp)
+{
+ int speed1 = *speedp, speed2 = *speedp;
+ int div1, div2;
+ int diff1, diff2;
+ int retval;
+
+ div1 = ess_calc_div (clock1, rev1, &speed1, &diff1);
+ div2 = ess_calc_div (clock2, rev2, &speed2, &diff2);
+
+ if (diff1 < diff2) {
+ *divp = div1;
+ *speedp = speed1;
+ retval = 1;
+ } else {
+ *divp = div2;
+ *speedp = speed2;
+ retval = 2;
+ }
- return 128 - divider;
+ return retval;
}
/*
@@ -299,30 +369,24 @@ static int ess_calc_div (int clock, int *speedp, int *diffp)
*/
static void ess_common_speed (sb_devc *devc, int *speedp, int *divp)
{
- int speed1 = *speedp, speed2 = *speedp;
- int div1, div2;
- int diff1, diff2;
+ int diff = 0, div;
- if (devc->caps & ESSCAP_NEW) {
- div1 = 0x000 | ess_calc_div (793800, &speed1, &diff1);
- div2 = 0x080 | ess_calc_div (768000, &speed2, &diff2);
+ if (devc->duplex) {
+ /*
+ * The 0x80 is important for the first audio channel
+ */
+ div = 0x80 | ess_calc_div (795500, 128, speedp, &diff);
+ } else if(devc->caps & SB_CAP_ES18XX_RATE) {
+ ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256,
+ &div, speedp);
} else {
if (*speedp > 22000) {
- div1 = 0x080 | ess_calc_div (795444, &speed1, &diff1);
- div2 = 0x180 | ess_calc_div (793800, &speed2, &diff2);
+ div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff);
} else {
- div1 = 0x000 | ess_calc_div (397722, &speed1, &diff1);
- div2 = 0x100 | ess_calc_div (396900, &speed2, &diff2);
+ div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff);
}
}
-
- if (diff1 < diff2) {
- *divp = div1;
- *speedp = speed1;
- } else {
- *divp = div2;
- *speedp = speed2;
- }
+ *divp = div;
}
static void ess_speed (sb_devc *devc, int audionum)
@@ -341,13 +405,21 @@ printk (KERN_INFO "FKS: ess_speed (%d) b speed = %d, div=%x\n", audionum, devc->
div2 = 256 - 7160000 / (speed * 82);
- if ((devc->caps & ESSCAP_NEW) && audionum != 1) {
- ess_setmixer (devc, 0x70, div);
- ess_setmixer (devc, 0x72, div2);
+ if (!devc->duplex) audionum = 1;
+
+ if (audionum == 1) {
+ /* Change behaviour of register A1 *
+ sb_chg_mixer(devc, 0x71, 0x20, 0x20)
+ * For ES1869 only??? */
+ ess_write (devc, 0xa1, div);
+ ess_write (devc, 0xa2, div2);
} else {
- ess_change (devc, 0xba, 0x40, (div & 0x100) ? 0x40 : 0x00);
- ess_write (devc, 0xa1, div & 0xff);
+ ess_setmixer (devc, 0x70, div);
+ /*
+ * FKS: fascinating: 0x72 doesn't seem to work.
+ */
ess_write (devc, 0xa2, div2);
+ ess_setmixer (devc, 0x72, div2);
}
}
@@ -355,14 +427,77 @@ static int ess_audio_prepare_for_input(int dev, int bsize, int bcount)
{
sb_devc *devc = audio_devs[dev]->devc;
+ ess_speed(devc, 1);
+
+ sb_dsp_command(devc, DSP_CMD_SPKOFF);
+
ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */
- ess_change (devc, 0xa8, 0x0b, 3 - devc->channels); /* Mono/stereo */
+ ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */
+ ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */
+ ess_exec_commands (devc, ess_inp_cmds);
+
+ ess_change (devc, 0xb1, 0xf0, 0x50);
+ ess_change (devc, 0xb2, 0xf0, 0x50);
+
+ devc->trigger_bits = 0;
+ return 0;
+}
+
+static int ess_audio_prepare_for_output_audio1 (int dev, int bsize, int bcount)
+{
+ sb_devc *devc = audio_devs[dev]->devc;
+
+ sb_dsp_reset(devc);
ess_speed(devc, 1);
+ ess_write (devc, 0xb8, 4); /* Auto init DMA mode */
+ ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */
+ ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */
+
+ ess_exec_commands (devc, ess_out_cmds);
+
+ ess_change (devc, 0xb1, 0xf0, 0x50); /* Enable DMA */
+ ess_change (devc, 0xb2, 0xf0, 0x50); /* Enable IRQ */
- ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51);
- ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) |
- ((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40));
+ sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */
+
+ devc->trigger_bits = 0;
+ return 0;
+}
+
+static int ess_audio_prepare_for_output_audio2 (int dev, int bsize, int bcount)
+{
+ sb_devc *devc = audio_devs[dev]->devc;
+ unsigned char bits;
+
+/* FKS: qqq
+ sb_dsp_reset(devc);
+*/
+
+ /*
+ * Auto-Initialize:
+ * DMA mode + demand mode (8 bytes/request, yes I want it all!)
+ * But leave 16-bit DMA bit untouched!
+ */
+ ess_chgmixer (devc, 0x78, 0xd0, 0xd0);
+
+ ess_speed(devc, 2);
+
+ /* bits 4:3 on ES1887 represent recording source. Keep them! */
+ bits = ess_getmixer (devc, 0x7a) & 0x18;
+
+ /* Set stereo/mono */
+ if (devc->channels != 1) bits |= 0x02;
+
+ /* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */
+ if (devc->bits != AFMT_U8) bits |= 0x05; /* 16 bit */
+
+ /* Enable DMA, IRQ will be shared (hopefully)*/
+ bits |= 0x60;
+
+ ess_setmixer (devc, 0x7a, bits);
+
+ ess_mixer_reload (devc, SOUND_MIXER_PCM); /* There be sound! */
devc->trigger_bits = 0;
return 0;
@@ -378,79 +513,144 @@ printk(KERN_INFO "ess_audio_prepare_for_output: dma_out=%d,dma_in=%d\n"
#endif
if (devc->duplex) {
- ess_speed(devc, 2);
+ return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount);
+ } else {
+ return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount);
+ }
+}
+
+static void ess_audio_halt_xfer(int dev)
+{
+ unsigned long flags;
+ sb_devc *devc = audio_devs[dev]->devc;
- ess_chgmixer (devc, 0x7a, 0x07, ((devc->bits & ESSFMT_SIGNED) ? 4 : 0) |
- ((devc->bits & ESSFMT_16) ? 1 : 0) | ((devc->channels > 1) ? 2 : 0));
+ save_flags(flags);
+ cli();
+ sb_dsp_reset(devc);
+ restore_flags(flags);
- if (devc->caps & ESSCAP_NEW)
- ess_mixer_reload (devc, SOUND_MIXER_PCM); /* There be sound! */
- else
- sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */
- } else {
- ess_write (devc, 0xb8, 4); /* Auto init DMA mode */
- ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */
+ /*
+ * Audio 2 may still be operational! Creates awful sounds!
+ */
+ if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00);
+}
- ess_speed(devc, 1);
+static void ess_audio_start_input
+ (int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+ int count = nr_bytes;
+ sb_devc *devc = audio_devs[dev]->devc;
+ short c = -nr_bytes;
- ess_write (devc, 0xb6, (devc->bits & ESSFMT_SIGNED) ? 0 : 0x80);
- ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51);
- ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) |
- ((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40));
+ /*
+ * Start a DMA input to the buffer pointed by dmaqtail
+ */
- sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */
- }
- devc->trigger_bits = 0;
- return 0;
+ if (audio_devs[dev]->dmap_in->dma > 3) count >>= 1;
+ count--;
+
+ devc->irq_mode = IMODE_INPUT;
+
+ ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+ ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+
+ ess_change (devc, 0xb8, 0x0f, 0x0f); /* Go */
+ devc->intr_active = 1;
}
-static void ess_audio_halt_xfer(int dev)
+static void ess_audio_output_block_audio1
+ (int dev, unsigned long buf, int nr_bytes, int intrflag)
{
+ int count = nr_bytes;
sb_devc *devc = audio_devs[dev]->devc;
+ short c = -nr_bytes;
- sb_dsp_command (devc, DSP_CMD_SPKOFF);
+ if (audio_devs[dev]->dmap_out->dma > 3)
+ count >>= 1;
+ count--;
- if (devc->caps & ESSCAP_NEW) {
- ess_setmixer (devc, 0x7c, 0);
- }
+ devc->irq_mode = IMODE_OUTPUT;
+
+ ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+ ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+
+ ess_change (devc, 0xb8, 0x05, 0x05); /* Go */
+ devc->intr_active = 1;
+}
- ess_change (devc, 0xb8, 0x0f, 0x00); /* Stop */
+static void ess_audio_output_block_audio2
+ (int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+ int count = nr_bytes;
+ sb_devc *devc = audio_devs[dev]->devc;
+ short c = -nr_bytes;
- if (devc->duplex) { /* Audio 2 may still be operational! */
- ess_chgmixer (devc, 0x78, 0x03, 0x00);
+ if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1;
+ count--;
+
+ ess_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff));
+ ess_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+ ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */
+
+ devc->irq_mode_16 = IMODE_OUTPUT;
+ devc->intr_active_16 = 1;
+}
+
+static void ess_audio_output_block
+ (int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+ sb_devc *devc = audio_devs[dev]->devc;
+
+ if (devc->duplex) {
+ ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag);
+ } else {
+ ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag);
}
}
+/*
+ * FKS: the if-statements for both bits and bits_16 are quite alike.
+ * Combine this...
+ */
static void ess_audio_trigger(int dev, int bits)
{
sb_devc *devc = audio_devs[dev]->devc;
- int bits_16 = bits & devc->irq_mode_16 & IMODE_OUTPUT;
+ int bits_16 = bits & devc->irq_mode_16;
bits &= devc->irq_mode;
if (!bits && !bits_16) {
- sb_dsp_command (devc, 0xd0); /* Halt DMA */
- ess_chgmixer (devc, 0x78, 0x04, 0x00); /* Halt DMA 2 */
+ /* FKS oh oh.... wrong?? for dma 16? */
+ sb_dsp_command(devc, 0xd0); /* Halt DMA */
}
if (bits) {
- short c = -devc->trg_bytes;
-
- ess_write (devc, 0xa4, (unsigned char)((unsigned short) c & 0xff));
- ess_write (devc, 0xa5, (unsigned char)((unsigned short) c >> 8));
- ess_change (devc, 0xb8, 0x0f, (devc->irq_mode==IMODE_INPUT)?0x0f:0x05);
+ switch (devc->irq_mode)
+ {
+ case IMODE_INPUT:
+ ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
+ devc->trg_intrflag);
+ break;
- devc->intr_active = 1;
+ case IMODE_OUTPUT:
+ ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
+ devc->trg_intrflag);
+ break;
+ }
}
if (bits_16) {
- short c = -devc->trg_bytes_16;
-
- ess_setmixer (devc, 0x74, (unsigned char)((unsigned short) c & 0xff));
- ess_setmixer (devc, 0x76, (unsigned char)((unsigned short) c >> 8));
- ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */
+ switch (devc->irq_mode_16) {
+ case IMODE_INPUT:
+ ess_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16,
+ devc->trg_intrflag_16);
+ break;
- devc->intr_active_16 = 1;
+ case IMODE_OUTPUT:
+ ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16,
+ devc->trg_intrflag_16);
+ break;
+ }
}
devc->trigger_bits = bits | bits_16;
@@ -462,8 +662,8 @@ static int ess_audio_set_speed(int dev, int speed)
int minspeed, maxspeed, dummydiv;
if (speed > 0) {
- minspeed = (devc->caps & ESSCAP_NEW) ? 6047 : 3125;
- maxspeed = 48000;
+ minspeed = (devc->duplex ? 6215 : 5000 );
+ maxspeed = (devc->duplex ? 44100 : 48000);
if (speed < minspeed) speed = minspeed;
if (speed > maxspeed) speed = maxspeed;
@@ -474,46 +674,38 @@ static int ess_audio_set_speed(int dev, int speed)
return devc->speed;
}
+/*
+ * FKS: This is a one-on-one copy of sb1_audio_set_bits
+ */
static unsigned int ess_audio_set_bits(int dev, unsigned int bits)
{
sb_devc *devc = audio_devs[dev]->devc;
- switch (bits) {
- case 0:
- break;
- case AFMT_S16_LE:
- devc->bits = ESSFMT_16 | ESSFMT_SIGNED;
- break;
- case AFMT_U16_LE:
- devc->bits = ESSFMT_16;
- break;
- case AFMT_S8:
- devc->bits = ESSFMT_SIGNED;
- break;
- default:
- devc->bits = 0;
- break;
+ if (bits != 0) {
+ if (bits == AFMT_U8 || bits == AFMT_S16_LE) {
+ devc->bits = bits;
+ } else {
+ devc->bits = AFMT_U8;
+ }
}
return devc->bits;
}
+/*
+ * FKS: This is a one-on-one copy of sbpro_audio_set_channels
+ * (*) Modified it!!
+ */
static short ess_audio_set_channels(int dev, short channels)
{
sb_devc *devc = audio_devs[dev]->devc;
- if (devc->fullduplex && !(devc->caps & ESSCAP_NEW)) {
- devc->channels = 1;
- } else {
- if (channels == 1 || channels == 2) {
- devc->channels = channels;
- }
- }
+ if (channels == 1 || channels == 2) devc->channels = channels;
return devc->channels;
}
-static struct audio_driver ess_audio_driver = /* ESS ES688/1688/18xx */
+static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */
{
sb_audio_open,
sb_audio_close,
@@ -540,7 +732,7 @@ struct audio_driver *ess_audio_init
(sb_devc *devc, int *audio_flags, int *format_mask)
{
*audio_flags = DMA_AUTOMODE;
- *format_mask |= AFMT_S16_LE | AFMT_U16_LE | AFMT_S8;
+ *format_mask |= AFMT_S16_LE;
if (devc->duplex) {
int tmp_dma;
@@ -563,8 +755,10 @@ struct audio_driver *ess_audio_init
* ESS common *
* *
****************************************************************************/
-static void ess_handle_channel (int dev, int irq_mode)
+static void ess_handle_channel
+ (char *channel, int dev, int intr_active, unsigned char flag, int irq_mode)
{
+ if (!intr_active || !flag) return;
#ifdef FKS_REG_LOGGING
printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);
#endif
@@ -586,77 +780,48 @@ printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);
}
/*
- * In the ESS 1888 model, how do we found out if the MPU interrupted ???
+ * FKS: TODO!!! Finish this!
+ *
+ * I think midi stuff uses uart401, without interrupts.
+ * So IMODE_MIDI isn't a value for devc->irq_mode.
*/
void ess_intr (sb_devc *devc)
{
int status;
unsigned char src;
- if (devc->caps & ESSCAP_PNP) {
- outb (devc->pcibase + 7, 0); /* Mask IRQs */
- src = inb (devc->pcibase + 6) & 0x0f;
- } else if (devc->caps & ESSCAP_IRQ) {
+ if (devc->submodel == SUBMDL_ES1887) {
src = ess_getmixer (devc, 0x7f) >> 4;
} else {
- src = inb (DSP_STATUS) & 0x01;
- if (devc->duplex && (ess_getmixer (devc, 0x7a) & 0x80)) {
- src |= 0x02;
- }
- if ((devc->caps & ESSCAP_ES18) && (ess_getmixer (devc, 0x64) & 0x10)) {
- src |= 0x04;
- }
-#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401)
- /*
- * This should work if dev_conf wasn't local to mpu401.c
- */
-#if 0
- if ((int)devc->midi_irq_cookie >= 0 &&
- !(inb(dev_conf[(int)devc->midi_irq_cookie].base + 1) & 0x80)) {
- src |= 0x08;
- }
-#endif
-#endif
+ src = 0xff;
}
#ifdef FKS_REG_LOGGING
printk(KERN_INFO "FKS: sbintr src=%x\n",(int)src);
#endif
- if (src & 0x01) {
- status = inb(DSP_DATA_AVAIL); /* Acknowledge interrupt */
- if (devc->intr_active)
- ess_handle_channel (devc->dev, devc->irq_mode );
- }
-
- if (src & 0x02) {
- ess_chgmixer (devc, 0x7a, 0x80, 0x00); /* Acknowledge interrupt */
- if (devc->intr_active_16)
- ess_handle_channel (devc->dev, devc->irq_mode_16);
+ ess_handle_channel
+ ( "Audio 1"
+ , devc->dev, devc->intr_active , src & 0x01, devc->irq_mode );
+ ess_handle_channel
+ ( "Audio 2"
+ , devc->dev, devc->intr_active_16, src & 0x02, devc->irq_mode_16);
+ /*
+ * Acknowledge interrupts
+ */
+ if (devc->submodel == SUBMDL_ES1887 && (src & 0x02)) {
+ ess_chgmixer (devc, 0x7a, 0x80, 0x00);
}
- if (src & 0x04) {
- int left, right;
-
- ess_setmixer (devc, 0x66, 0x00); /* Hardware volume IRQ ack */
-
- left = ess_getmixer (devc, 0x60);
- right = ess_getmixer (devc, 0x62);
-
- left = (left & 0x40) ? 0 : ((left * 100 + 31)/ 63); /* Mute or scale */
- right = (right & 0x40) ? 0 : ((right * 100 + 31)/ 63);
-
- devc->levels[SOUND_MIXER_VOLUME] = left | (right << 8);
+ if (src & 0x01) {
+ status = inb(DSP_DATA_AVAIL);
}
+}
-#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401)
- if ((int)devc->midi_irq_cookie >= 0 && (src & 0x08)) {
- mpuintr (devc->irq, devc->midi_irq_cookie, NULL);
- }
-#endif
+static void ess_extended (sb_devc * devc)
+{
+ /* Enable extended mode */
- if (devc->caps & ESSCAP_PNP) {
- outb (devc->pcibase + 7, 0xff); /* Unmask IRQs */
- }
+ sb_dsp_command(devc, 0xc6);
}
static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data)
@@ -686,7 +851,7 @@ static int ess_read (sb_devc * devc, unsigned char reg)
int ess_dsp_reset(sb_devc * devc)
{
- int loopc, val;
+ int loopc;
#ifdef FKS_REG_LOGGING
printk(KERN_INFO "FKS: ess_dsp_reset 1\n");
@@ -707,102 +872,79 @@ ess_show_mixerregs (devc);
DDB(printk("sb: No response to RESET\n"));
return 0; /* Sorry */
}
+ ess_extended (devc);
- sb_dsp_command(devc, 0xc6); /* Enable extended mode */
- if (!(devc->caps & ESSCAP_PNP)) {
- ess_setmixer (devc, 0x40, 0x03); /* Enable joystick and OPL3 */
+ DEB(printk("sb_dsp_reset() OK\n"));
- switch (devc->irq) {
- case 2:
- case 9:
- val = 1;
- break;
- case 5:
- val = 2;
- break;
- case 7:
- val = 3;
- break;
- case 10:
- val = 4;
- break;
- case 11:
- val = 5;
- break;
- default:
- val = 0;
- } /* IRQ config */
- ess_write (devc, 0xb1, 0xf0 | ((val && val != 5) ? val - 1 : 0));
+#ifdef FKS_LOGGING
+printk(KERN_INFO "FKS: dsp_reset 2\n");
+ess_show_mixerregs (devc);
+#endif
- if (devc->caps & ESSCAP_IRQ) {
- ess_setmixer (devc, 0x7f, 0x01 | (val << 1)); /* IRQ config */
- }
+ return 1;
+}
- switch ((devc->duplex) ? devc->dma16 : devc->dma8) {
- case 0:
- val = 0x54;
- break;
- case 1:
- val = 0x58;
- break;
- case 3:
- val = 0x5c;
- break;
- default:
- val = 0;
- }
- ess_write (devc, 0xb2, val); /* DMA1 config */
+static int ess_irq_bits (int irq)
+{
+ switch (irq) {
+ case 2:
+ case 9:
+ return 0;
- if (devc->duplex) {
- switch (devc->dma8) {
- case 0:
- val = 0x04;
- break;
- case 1:
- val = 0x05;
- break;
- case 3:
- val = 0x06;
- break;
- case 5:
- val = 0x07;
- break;
- default:
- val = 0;
- }
- ess_write (devc, 0x7d, val); /* DMA2 config */
- }
- }
- ess_change (devc, 0xb1, 0xf0, 0x50); /* Enable IRQ 1 */
- ess_change (devc, 0xb2, 0xf0, 0x50); /* Enable DMA 1 */
- ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */
- ess_setmixer (devc, 0x7a, 0x40); /* Enable IRQ 2 */
- /* Auto-Initialize DMA mode + demand mode (8 bytes/request) */
- if (devc->caps & ESSCAP_PNP) {
- ess_setmixer (devc, 0x78, 0xd0);
- ess_setmixer (devc, 0x64, 0x82); /* Enable HW volume interrupt */
- } else {
- ess_setmixer (devc, 0x78, (devc->dma8 > 4) ? 0xf0 : 0xd0);
- ess_setmixer (devc, 0x64, 0x42); /* Enable HW volume interrupt */
- }
+ case 5:
+ return 1;
- if (devc->caps & ESSCAP_NEW) {
- ess_setmixer (devc, 0x71, 0x32); /* Change behaviour of register A1 */
- ess_setmixer (devc, 0x1c, 0x05); /* Recording source is mixer */
- } else {
- ess_change (devc, 0xb7, 0x80, 0x80); /* Enable DMA FIFO */
+ case 7:
+ return 2;
+
+ case 10:
+ return 3;
+
+ default:
+ printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq);
+ return -1;
}
+}
- DEB(printk("sb_dsp_reset() OK\n"));
+/*
+ * Set IRQ configuration register for all ESS models
+ */
+static int ess_common_set_irq_hw (sb_devc * devc)
+{
+ int irq_bits;
-#ifdef FKS_LOGGING
-printk(KERN_INFO "FKS: dsp_reset 2\n");
-ess_show_mixerregs (devc);
-#endif
+ if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return 0;
+ if (!ess_write (devc, 0xb1, 0x50 | (irq_bits << 2))) {
+ printk(KERN_ERR "ES1688: Failed to write to IRQ config register\n");
+ return 0;
+ }
return 1;
}
+/*
+ * I wanna use modern ES1887 mixer irq handling. Funny is the
+ * fact that my BIOS wants the same. But suppose someone's BIOS
+ * doesn't do this!
+ * This is independent of duplex. If there's a 1887 this will
+ * prevent it from going into 1888 mode.
+ */
+static void ess_es1887_set_irq_hw (sb_devc * devc)
+{
+ int irq_bits;
+
+ if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return;
+
+ ess_chgmixer (devc, 0x7f, 0x0f, 0x01 | ((irq_bits + 1) << 1));
+}
+
+static int ess_set_irq_hw (sb_devc * devc)
+{
+ if (devc->submodel == SUBMDL_ES1887) ess_es1887_set_irq_hw (devc);
+
+ return ess_common_set_irq_hw (devc);
+}
+
#ifdef FKS_TEST
/*
@@ -826,7 +968,7 @@ printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff));
};
#endif
-static unsigned int ess_identify (sb_devc * devc, int *control)
+static unsigned int ess_identify (sb_devc * devc)
{
unsigned int val;
unsigned long flags;
@@ -840,15 +982,8 @@ static unsigned int ess_identify (sb_devc * devc, int *control)
udelay(20);
val |= inb(MIXER_DATA);
udelay(20);
- *control = inb(MIXER_DATA) << 8;
- udelay(20);
- *control |= inb(MIXER_DATA);
- udelay(20);
restore_flags(flags);
- if (*control < 0 || *control > 0x3ff || check_region (*control, 8))
- *control = 0;
-
return val;
}
@@ -875,6 +1010,7 @@ static int ess_probe (sb_devc * devc, int reg, int xorval)
int ess_init(sb_devc * devc, struct address_info *hw_config)
{
+ unsigned char cfg;
int ess_major = 0, ess_minor = 0;
int i;
static char name[100], modelname[10];
@@ -882,7 +1018,6 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
/*
* Try to detect ESS chips.
*/
- devc->pcibase = 0;
sb_dsp_command(devc, 0xe7); /* Return identification */
@@ -934,10 +1069,10 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
case ESSTYPE_LIKE20:
break;
case 688:
- submodel = SUBMDL_ES688;
+ submodel = 0x00;
break;
case 1688:
- submodel = SUBMDL_ES1688;
+ submodel = 0x08;
break;
case 1868:
submodel = SUBMDL_ES1868;
@@ -986,7 +1121,7 @@ FKS_test (devc);
if (chip == NULL) {
int type;
- type = ess_identify (devc, &devc->pcibase);
+ type = ess_identify (devc);
switch (type) {
case 0x1868:
@@ -1063,72 +1198,139 @@ FKS_test (devc);
strcpy(name, "Jazz16");
}
- switch (devc->submodel) {
- case SUBMDL_ES1869:
- case SUBMDL_ES1879:
- devc->caps |= ESSCAP_NEW;
- case SUBMDL_ES1868:
- case SUBMDL_ES1878:
- devc->caps |= ESSCAP_PNP | ESSCAP_ES18;
- break;
- case SUBMDL_ES1887:
- devc->caps |= ESSCAP_IRQ;
- case SUBMDL_ES1888:
- devc->caps |= ESSCAP_NEW | ESSCAP_ES18;
+ /* AAS: info stolen from ALSA: these boards have different clocks */
+ switch(devc->submodel) {
+ case SUBMDL_ES1869:
+ case SUBMDL_ES1887:
+ case SUBMDL_ES1888:
+ devc->caps |= SB_CAP_ES18XX_RATE;
+ break;
}
- if (devc->caps & ESSCAP_PNP) {
- if (!devc->pcibase) {
- printk (KERN_ERR "ESS PnP chip without PnP registers. Ignored\n");
- return 0;
- }
- request_region (devc->pcibase, 8, "ESS18xx ctrl");
-
- outb (0x07, devc->pcibase); /* Selects logical device #1 */
- outb (0x01, devc->pcibase + 1);
- outb (0x28, devc->pcibase);
- i = inb (devc->pcibase + 1) & 0x0f;
- outb (0x28, devc->pcibase); /* Sets HW volume IRQ */
- outb (devc->irq << 4 | i, devc->pcibase + 1);
- outb (0x70, devc->pcibase); /* Sets IRQ 1 */
- outb (devc->irq, devc->pcibase + 1);
- outb (0x72, devc->pcibase); /* Sets IRQ 2 */
- outb (devc->irq, devc->pcibase + 1);
- outb (0x74, devc->pcibase); /* Sets DMA 1 */
- outb (hw_config->dma, devc->pcibase + 1);
- outb (0x75, devc->pcibase); /* Sets DMA 2 */
- outb (hw_config->dma2 >= 0 ? hw_config->dma2 : 4, devc->pcibase + 1);
- } else if (devc->pcibase) {
- printk (KERN_INFO "Non-PnP ESS card with PnP registers at %04Xh, ignoring them.\n", devc->pcibase);
- devc->pcibase = 0;
+
+ hw_config->name = name;
+ /* FKS: sb_dsp_reset to enable extended mode???? */
+ sb_dsp_reset(devc); /* Turn on extended mode */
+
+ /*
+ * Enable joystick and OPL3
+ */
+ cfg = ess_getmixer (devc, 0x40);
+ ess_setmixer (devc, 0x40, cfg | 0x03);
+ if (devc->submodel >= 8) { /* ES1688 */
+ devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */
}
+ sb_dsp_reset (devc);
- devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */
+ /*
+ * This is important! If it's not done, the IRQ probe in sb_dsp_init
+ * may fail.
+ */
+ return ess_set_irq_hw (devc);
+}
- hw_config->name = name;
+static int ess_set_dma_hw(sb_devc * devc)
+{
+ unsigned char cfg, dma_bits = 0, dma16_bits;
+ int dma;
- sb_dsp_reset(devc); /* Turn on extended mode */
+#ifdef FKS_LOGGING
+printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n"
+, devc->dma8, devc->dma16, devc->duplex);
+#endif
+
+ /*
+ * FKS: It seems as if this duplex flag isn't set yet. Check it.
+ */
+ dma = devc->dma8;
+
+ if (dma > 3 || dma < 0 || dma == 2) {
+ dma_bits = 0;
+ printk(KERN_ERR "ESS1688: Invalid DMA8 %d\n", dma);
+ return 0;
+ } else {
+ /* Extended mode DMA enable */
+ cfg = 0x50;
+
+ if (dma == 3) {
+ dma_bits = 3;
+ } else {
+ dma_bits = dma + 1;
+ }
+ }
+
+ if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) {
+ printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n");
+ return 0;
+ }
- ess_setmixer (devc, 0x00, 0x00); /* Reset mixer registers */
+ if (devc->duplex) {
+ dma = devc->dma16;
+ dma16_bits = 0;
+ if (dma >= 0) {
+ switch (dma) {
+ case 0:
+ dma_bits = 0x04;
+ break;
+ case 1:
+ dma_bits = 0x05;
+ break;
+ case 3:
+ dma_bits = 0x06;
+ break;
+ case 5:
+ dma_bits = 0x07;
+ dma16_bits = 0x20;
+ break;
+ default:
+ printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma);
+ return 0;
+ };
+ ess_chgmixer (devc, 0x78, 0x20, dma16_bits);
+ ess_chgmixer (devc, 0x7d, 0x07, dma_bits);
+ }
+ }
return 1;
}
/*
* This one is called from sb_dsp_init.
+ *
+ * Return values:
+ * 0: Failed
+ * 1: Succeeded or doesn't apply (not SUBMDL_ES1887)
*/
int ess_dsp_init (sb_devc *devc, struct address_info *hw_config)
{
/*
+ * This for ES1887 to run Full Duplex. Actually ES1888
+ * is allowed to do so too. I have no idea yet if this
+ * will work for ES1888 however.
+ *
* For SB16 having both dma8 and dma16 means enable
- * Full Duplex. Let's try this too
+ * Full Duplex. Let's try this for ES1887 too
+ *
*/
- if ((devc->caps & ESSCAP_ES18) && hw_config->dma2 >= 0) {
- devc->dma16 = hw_config->dma2;
- if (devc->dma8 != devc->dma16) {
+ if (devc->submodel == SUBMDL_ES1887) {
+ if (hw_config->dma2 != -1) {
+ devc->dma16 = hw_config->dma2;
+ }
+ /*
+ * devc->duplex initialization is put here, cause
+ * ess_set_dma_hw needs it.
+ */
+ if (devc->dma8 != devc->dma16 && devc->dma16 != -1) {
devc->duplex = 1;
}
+
+ if (!ess_set_dma_hw (devc)) {
+ free_irq(devc->irq, devc);
+ return 0;
+ }
+ return 1;
+ } else {
+ return -1;
}
- return 1;
}
/****************************************************************************
@@ -1149,13 +1351,13 @@ int ess_dsp_init (sb_devc *devc, struct address_info *hw_config)
#define ES1688_MIXER_DEVICES \
( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV )
-#define ES_NEW_RECORDING_DEVICES \
+#define ES1887_RECORDING_DEVICES \
( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH)
-#define ES_NEW_MIXER_DEVICES \
+#define ES1887_MIXER_DEVICES \
( ES1688_MIXER_DEVICES )
/*
- * Mixer registers of ES18xx with new capabilities
+ * Mixer registers of ES1887
*
* These registers specifically take care of recording levels. To make the
* mapping from playback devices to recording devices every recording
@@ -1285,11 +1487,11 @@ MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
};
/*
- * This one is for new ES's. It's little different from es_rec_mix: it
- * has 0x7c for PCM playback level. This is because uses
+ * This one is for ES1887. It's little different from es_rec_mix: it
+ * has 0x7c for PCM playback level. This is because ES1887 uses
* Audio 2 for playback.
*/
-static mixer_tab es_new_mix = {
+static mixer_tab es1887_mix = {
MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6),
MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
@@ -1323,6 +1525,16 @@ MIX_ENT(ES_REC_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),
MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
};
+static int ess_has_rec_mixer (int submodel)
+{
+ switch (submodel) {
+ case SUBMDL_ES1887:
+ return 1;
+ default:
+ return 0;
+ };
+};
+
#ifdef FKS_LOGGING
static int ess_mixer_mon_regs[]
= { 0x70, 0x71, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7f
@@ -1353,13 +1565,15 @@ printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value);
save_flags(flags);
cli();
+ if (port >= 0xa0) {
+ ess_write (devc, port, value);
+ } else {
+ outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
- outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
-
- udelay(20);
- outb(((unsigned char) (value & 0xff)), MIXER_DATA);
- udelay(20);
-
+ udelay(20);
+ outb(((unsigned char) (value & 0xff)), MIXER_DATA);
+ udelay(20);
+ };
restore_flags(flags);
}
@@ -1371,12 +1585,15 @@ unsigned int ess_getmixer (sb_devc * devc, unsigned int port)
save_flags(flags);
cli();
- outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
-
- udelay(20);
- val = inb(MIXER_DATA);
- udelay(20);
+ if (port >= 0xa0) {
+ val = ess_read (devc, port);
+ } else {
+ outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
+ udelay(20);
+ val = inb(MIXER_DATA);
+ udelay(20);
+ }
restore_flags(flags);
return val;
@@ -1400,21 +1617,23 @@ void ess_mixer_init (sb_devc * devc)
devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
/*
- * Take care of new ES's specifics...
+ * Take care of ES1887 specifics...
*/
- if (devc->caps & ESSCAP_NEW) {
- devc->supported_devices = ES_NEW_MIXER_DEVICES;
- devc->supported_rec_devices = ES_NEW_RECORDING_DEVICES;
+ switch (devc->submodel) {
+ case SUBMDL_ES1887:
+ devc->supported_devices = ES1887_MIXER_DEVICES;
+ devc->supported_rec_devices = ES1887_RECORDING_DEVICES;
#ifdef FKS_LOGGING
printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
#endif
if (devc->duplex) {
- devc->iomap = &es_new_mix;
+ devc->iomap = &es1887_mix;
} else {
devc->iomap = &es_rec_mix;
}
- } else {
- if (devc->submodel == SUBMDL_ES688) {
+ break;
+ default:
+ if (devc->submodel < 8) {
devc->supported_devices = ES688_MIXER_DEVICES;
devc->supported_rec_devices = ES688_RECORDING_DEVICES;
devc->iomap = &es688_mix;
@@ -1425,10 +1644,10 @@ printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
*/
devc->supported_devices = ES1688_MIXER_DEVICES;
devc->supported_rec_devices = ES1688_RECORDING_DEVICES;
- if (devc->caps & ESSCAP_ES18) {
- devc->iomap = &es1688later_mix;
- } else {
+ if (devc->submodel < 0x10) {
devc->iomap = &es1688_mix;
+ } else {
+ devc->iomap = &es1688later_mix;
}
}
}
@@ -1440,15 +1659,9 @@ printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
*/
int ess_mixer_set(sb_devc *devc, int dev, int left, int right)
{
- if ((devc->caps & ESSCAP_NEW) && (devc->recmask & (1 << dev))) {
+ if (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) {
sb_common_mixer_set (devc, dev + ES_REC_MIXER_RECDIFF, left, right);
}
- /* Set & unmute master volume */
- if ((devc->caps & ESSCAP_ES18) && (dev == SOUND_MIXER_VOLUME)) {
- ess_chgmixer (devc, 0x60, 0x7f, 0x3f & ((left * 0x3f + 50) / 100));
- ess_chgmixer (devc, 0x62, 0x7f, 0x3f & ((right * 0x3f + 50) / 100));
- return left | (right << 8);
- }
return sb_common_mixer_set (devc, dev, left, right);
}
@@ -1494,6 +1707,7 @@ printk (KERN_INFO "FKS: es_rec_set_recmask mask = %x\n", mask);
right = (value & 0x0000ff00) >> 8;
} else { /* Turn it off (3) */
left = 0;
+ left = 0;
right = 0;
}
sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right);
@@ -1506,7 +1720,7 @@ int ess_set_recmask(sb_devc * devc, int *mask)
{
/* This applies to ESS chips with record mixers only! */
- if (devc->caps & ESSCAP_NEW) {
+ if (ess_has_rec_mixer (devc->submodel)) {
*mask = es_rec_set_recmask (devc, *mask);
return 1; /* Applied */
} else {
@@ -1522,7 +1736,18 @@ int ess_mixer_reset (sb_devc * devc)
/*
* Separate actions for ESS chips with a record mixer:
*/
- if (devc->caps & ESSCAP_NEW) {
+ if (ess_has_rec_mixer (devc->submodel)) {
+ switch (devc->submodel) {
+ case SUBMDL_ES1887:
+ /*
+ * Separate actions for ES1887:
+ * Change registers 7a and 1c to make the record mixer the
+ * actual recording source.
+ */
+ ess_chgmixer(devc, 0x7a, 0x18, 0x08);
+ ess_chgmixer(devc, 0x1c, 0x07, 0x07);
+ break;
+ };
/*
* Call set_recmask for proper initialization
*/
@@ -1542,80 +1767,50 @@ int ess_mixer_reset (sb_devc * devc)
* *
****************************************************************************/
+/*
+ * FKS: IRQ may be shared. Hm. And if so? Then What?
+ */
int ess_midi_init(sb_devc * devc, struct address_info *hw_config)
{
- int val;
+ unsigned char cfg, tmp;
- if (devc->submodel == SUBMDL_ES688) {
- return 0; /* ES688 doesn't support MPU401 mode */
+ cfg = ess_getmixer (devc, 0x40) & 0x03;
+
+ if (devc->submodel < 8) {
+ ess_setmixer (devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */
+ return 0; /* ES688 doesn't support MPU401 mode */
}
+ tmp = (hw_config->io_base & 0x0f0) >> 4;
- if (hw_config->irq < 2) {
- hw_config->irq = devc->irq;
+ if (tmp > 3) {
+ ess_setmixer (devc, 0x40, cfg);
+ return 0;
}
+ cfg |= tmp << 3;
- if (devc->caps & ESSCAP_PNP) {
- outb (0x07, devc->pcibase); /* Selects logical device #1 */
- outb (0x01, devc->pcibase + 1);
- outb (0x28, devc->pcibase);
- val = inb (devc->pcibase + 1) & 0xf0;
- outb (0x28, devc->pcibase); /* Sets MPU IRQ */
- outb (hw_config->irq | val, devc->pcibase + 1);
- if (hw_config->io_base) {
- outb (0x64, devc->pcibase); /* Sets MPU I/O address */
- outb ((hw_config->io_base & 0xf00) >> 8, devc->pcibase + 1);
- outb (0x65, devc->pcibase); /* Sets MPU I/O address */
- outb (hw_config->io_base & 0xfc, devc->pcibase + 1);
- } else {
- outb (0x64, devc->pcibase); /* Read MPU I/O address */
- hw_config->io_base = (inb (devc->pcibase + 1) & 0x0f) << 8;
- outb (0x65, devc->pcibase); /* Read MPU I/O address */
- hw_config->io_base |= inb (devc->pcibase + 1) & 0xfc;
- }
+ tmp = 1; /* MPU enabled without interrupts */
- ess_setmixer (devc, 0x64, 0xc2); /* Enable MPU interrupt */
- } else {
- if (devc->irq == hw_config->irq && (devc->caps & ESSCAP_IRQ)) {
- val = 0x43;
- }
- else switch (hw_config->irq) {
- case 11:
- if (!(devc->caps & ESSCAP_IRQ)) {
- return 0;
- }
- val = 0x63;
- break;
- case 2:
- case 9:
- val = 0x83;
- break;
- case 5:
- val = 0xa3;
- break;
- case 7:
- val = 0xc3;
- break;
- case 10:
- val = 0xe3;
- break;
- default:
- return 0;
- }
- switch (hw_config->io_base) {
- case 0x300:
- case 0x310:
- case 0x320:
- case 0x330:
- ess_setmixer (devc, 0x40, val
- | ((hw_config->io_base & 0x0f0) >> 1));
- break;
- default:
- return 0;
- }
+ /* May be shared: if so the value is -ve */
+
+ switch (abs(hw_config->irq)) {
+ case 9:
+ tmp = 0x4;
+ break;
+ case 5:
+ tmp = 0x5;
+ break;
+ case 7:
+ tmp = 0x6;
+ break;
+ case 10:
+ tmp = 0x7;
+ break;
+ default:
+ return 0;
}
- if (devc->irq == hw_config->irq) /* Shared IRQ */
- hw_config->irq = -devc->irq;
+ cfg |= tmp << 5;
+ ess_setmixer (devc, 0x40, cfg | 0x03);
return 1;
}