summaryrefslogtreecommitdiffstats
path: root/drivers/sound/sb_ess.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-17 13:25:08 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-17 13:25:08 +0000
commit59223edaa18759982db0a8aced0e77457d10c68e (patch)
tree89354903b01fa0a447bffeefe00df3044495db2e /drivers/sound/sb_ess.c
parentdb7d4daea91e105e3859cf461d7e53b9b77454b2 (diff)
Merge with Linux 2.3.6. Sorry, this isn't tested on silicon, I don't
have a MIPS box at hand.
Diffstat (limited to 'drivers/sound/sb_ess.c')
-rw-r--r--drivers/sound/sb_ess.c1018
1 files changed, 427 insertions, 591 deletions
diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c
index 635be8a11..c6eb5c8d5 100644
--- a/drivers/sound/sb_ess.c
+++ b/drivers/sound/sb_ess.c
@@ -40,6 +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.
*
* 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
@@ -192,12 +196,27 @@
int esstype = ESSTYPE_LIKE20; /* 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_ES1887 0x14 /* Subtype ES1887 for specific handling */
-#define SUBMDL_ES1888 0x15 /* Subtype ES1888 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
#ifdef FKS_LOGGING
static void ess_show_mixerregs (sb_devc *devc);
@@ -213,52 +232,6 @@ 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)
{
@@ -298,56 +271,22 @@ static void ess_set_input_parms
devc->irq_mode = IMODE_INPUT;
}
-static int ess_calc_div (int clock, int revert, int *speedp, int *diffp)
+static int ess_calc_div (int clock, int *speedp, int *diffp)
{
int divider;
int speed, diff;
- int retval;
speed = *speedp;
divider = (clock + speed / 2) / speed;
- retval = revert - divider;
- if (retval > revert - 1) {
- retval = revert - 1;
- divider = revert - retval;
+ if (divider > 127) {
+ divider = 127;
}
- /* 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;
- if (diff < 0) diff =-diff;
- *diffp = diff;
-
- return retval;
-}
-
-#ifdef OBSOLETE
-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);
+ *diffp = diff < 0 ? -diff : diff;
- if (diff1 < diff2) {
- *divp = div1;
- *speedp = speed1;
- retval = 1;
- } else {
- *divp = div2;
- *speedp = speed2;
- retval = 2;
- }
-
- return retval;
+ return 128 - divider;
}
-#endif
/*
* Depending on the audiochannel ESS devices can
@@ -359,21 +298,30 @@ static int ess_calc_best_speed
*/
static void ess_common_speed (sb_devc *devc, int *speedp, int *divp)
{
- int diff = 0, div;
+ int speed1 = *speedp, speed2 = *speedp;
+ int div1, div2;
+ int diff1, diff2;
- if (devc->duplex) {
- /*
- * The 0x80 is important for the first audio channel
- */
- div = 0x80 | ess_calc_div (795500, 128, speedp, &diff);
+ if (devc->caps & ESSCAP_NEW) {
+ div1 = 0x000 | ess_calc_div (793800, &speed1, &diff1);
+ div2 = 0x080 | ess_calc_div (768000, &speed2, &diff2);
} else {
if (*speedp > 22000) {
- div = 0x80 | ess_calc_div (795500, 256, speedp, &diff);
+ div1 = 0x080 | ess_calc_div (795444, &speed1, &diff1);
+ div2 = 0x180 | ess_calc_div (793800, &speed2, &diff2);
} else {
- div = 0x00 | ess_calc_div (397700, 128, speedp, &diff);
+ div1 = 0x000 | ess_calc_div (397722, &speed1, &diff1);
+ div2 = 0x100 | ess_calc_div (396900, &speed2, &diff2);
}
}
- *divp = div;
+
+ if (diff1 < diff2) {
+ *divp = div1;
+ *speedp = speed1;
+ } else {
+ *divp = div2;
+ *speedp = speed2;
+ }
}
static void ess_speed (sb_devc *devc, int audionum)
@@ -392,21 +340,13 @@ printk (KERN_INFO "FKS: ess_speed (%d) b speed = %d, div=%x\n", audionum, devc->
div2 = 256 - 7160000 / (speed * 82);
- 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 {
+ if ((devc->caps & ESSCAP_NEW) && audionum != 1) {
ess_setmixer (devc, 0x70, div);
- /*
- * FKS: fascinating: 0x72 doesn't seem to work.
- */
- ess_write (devc, 0xa2, div2);
ess_setmixer (devc, 0x72, div2);
+ } else {
+ ess_change (devc, 0xba, 0x40, (div & 0x100) ? 0x40 : 0x00);
+ ess_write (devc, 0xa1, div & 0xff);
+ ess_write (devc, 0xa2, div2);
}
}
@@ -414,77 +354,14 @@ 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, 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, 0xa8, 0x0b, 3 - devc->channels); /* Mono/stereo */
- 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 */
-
- 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! */
+ 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));
devc->trigger_bits = 0;
return 0;
@@ -500,144 +377,79 @@ printk(KERN_INFO "ess_audio_prepare_for_output: dma_out=%d,dma_in=%d\n"
#endif
if (devc->duplex) {
- return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount);
- } else {
- return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount);
- }
-}
+ ess_speed(devc, 2);
-static void ess_audio_halt_xfer(int dev)
-{
- unsigned long flags;
- sb_devc *devc = audio_devs[dev]->devc;
-
- save_flags(flags);
- cli();
- sb_dsp_reset(devc);
- restore_flags(flags);
-
- /*
- * Audio 2 may still be operational! Creates awful sounds!
- */
- if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00);
-}
-
-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;
-
- /*
- * Start a DMA input to the buffer pointed by dmaqtail
- */
-
- 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_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;
+ ess_chgmixer (devc, 0x7a, 0x07, ((devc->bits & ESSFMT_SIGNED) ? 4 : 0) |
+ ((devc->bits & ESSFMT_16) ? 1 : 0) | ((devc->channels > 1) ? 2 : 0));
- if (audio_devs[dev]->dmap_out->dma > 3)
- count >>= 1;
- count--;
+ 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 */
- devc->irq_mode = IMODE_OUTPUT;
+ ess_speed(devc, 1);
- ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
- ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+ 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));
- ess_change (devc, 0xb8, 0x05, 0x05); /* Go */
- devc->intr_active = 1;
+ sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */
+ }
+ devc->trigger_bits = 0;
+ return 0;
}
-static void ess_audio_output_block_audio2
- (int dev, unsigned long buf, int nr_bytes, int intrflag)
+static void ess_audio_halt_xfer(int dev)
{
- int count = nr_bytes;
sb_devc *devc = audio_devs[dev]->devc;
- short c = -nr_bytes;
- if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1;
- count--;
+ sb_dsp_command (devc, DSP_CMD_SPKOFF);
- 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;
-}
+ if (devc->caps & ESSCAP_NEW) {
+ ess_setmixer (devc, 0x7c, 0);
+ }
-static void ess_audio_output_block
- (int dev, unsigned long buf, int nr_bytes, int intrflag)
-{
- sb_devc *devc = audio_devs[dev]->devc;
+ ess_change (devc, 0xb8, 0x0f, 0x00); /* Stop */
- if (devc->duplex) {
- ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag);
- } else {
- ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag);
+ if (devc->duplex) { /* Audio 2 may still be operational! */
+ ess_chgmixer (devc, 0x78, 0x03, 0x00);
}
}
-/*
- * 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;
+ int bits_16 = bits & devc->irq_mode_16 & IMODE_OUTPUT;
bits &= devc->irq_mode;
if (!bits && !bits_16) {
- /* FKS oh oh.... wrong?? for dma 16? */
- sb_dsp_command(devc, 0xd0); /* Halt DMA */
+ sb_dsp_command (devc, 0xd0); /* Halt DMA */
+ ess_chgmixer (devc, 0x78, 0x04, 0x00); /* Halt DMA 2 */
}
if (bits) {
- switch (devc->irq_mode)
- {
- case IMODE_INPUT:
- ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
- devc->trg_intrflag);
- break;
+ short c = -devc->trg_bytes;
- case IMODE_OUTPUT:
- ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
- devc->trg_intrflag);
- break;
- }
+ 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);
+
+ devc->intr_active = 1;
}
if (bits_16) {
- 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;
+ short c = -devc->trg_bytes_16;
- case IMODE_OUTPUT:
- ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16,
- devc->trg_intrflag_16);
- break;
- }
+ 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 */
+
+ devc->intr_active_16 = 1;
}
devc->trigger_bits = bits | bits_16;
@@ -649,8 +461,8 @@ static int ess_audio_set_speed(int dev, int speed)
int minspeed, maxspeed, dummydiv;
if (speed > 0) {
- minspeed = (devc->duplex ? 6215 : 5000 );
- maxspeed = (devc->duplex ? 44100 : 48000);
+ minspeed = (devc->caps & ESSCAP_NEW) ? 6047 : 3125;
+ maxspeed = 48000;
if (speed < minspeed) speed = minspeed;
if (speed > maxspeed) speed = maxspeed;
@@ -661,38 +473,46 @@ 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;
- if (bits != 0) {
- if (bits == AFMT_U8 || bits == AFMT_S16_LE) {
- devc->bits = bits;
- } else {
- devc->bits = AFMT_U8;
- }
+ 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;
}
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 (channels == 1 || channels == 2) devc->channels = channels;
+ if (devc->fullduplex && !(devc->caps & ESSCAP_NEW)) {
+ devc->channels = 1;
+ } else {
+ if (channels == 1 || channels == 2) {
+ devc->channels = channels;
+ }
+ }
return devc->channels;
}
-static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */
+static struct audio_driver ess_audio_driver = /* ESS ES688/1688/18xx */
{
sb_audio_open,
sb_audio_close,
@@ -719,7 +539,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;
+ *format_mask |= AFMT_S16_LE | AFMT_U16_LE | AFMT_S8;
if (devc->duplex) {
int tmp_dma;
@@ -742,10 +562,8 @@ struct audio_driver *ess_audio_init
* ESS common *
* *
****************************************************************************/
-static void ess_handle_channel
- (char *channel, int dev, int intr_active, unsigned char flag, int irq_mode)
+static void ess_handle_channel (int dev, 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
@@ -767,48 +585,77 @@ printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);
}
/*
- * FKS: TODO!!! Finish this!
- *
- * I think midi stuff uses uart401, without interrupts.
- * So IMODE_MIDI isn't a value for devc->irq_mode.
+ * In the ESS 1888 model, how do we found out if the MPU interrupted ???
*/
void ess_intr (sb_devc *devc)
{
int status;
unsigned char src;
- if (devc->submodel == SUBMDL_ES1887) {
+ if (devc->caps & ESSCAP_PNP) {
+ outb (devc->pcibase + 7, 0); /* Mask IRQs */
+ src = inb (devc->pcibase + 6) & 0x0f;
+ } else if (devc->caps & ESSCAP_IRQ) {
src = ess_getmixer (devc, 0x7f) >> 4;
} else {
- src = 0xff;
+ 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
}
#ifdef FKS_REG_LOGGING
printk(KERN_INFO "FKS: sbintr src=%x\n",(int)src);
#endif
- 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 & 0x01) {
+ status = inb(DSP_DATA_AVAIL); /* Acknowledge interrupt */
+ if (devc->intr_active)
+ ess_handle_channel (devc->dev, devc->irq_mode );
}
- if (src & 0x01) {
- status = inb(DSP_DATA_AVAIL);
+ 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);
}
-}
-static void ess_extended (sb_devc * devc)
-{
- /* Enable extended mode */
+ 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);
- sb_dsp_command(devc, 0xc6);
+ 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 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
+
+ if (devc->caps & ESSCAP_PNP) {
+ outb (devc->pcibase + 7, 0xff); /* Unmask IRQs */
+ }
}
static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data)
@@ -838,7 +685,7 @@ static int ess_read (sb_devc * devc, unsigned char reg)
int ess_dsp_reset(sb_devc * devc)
{
- int loopc;
+ int loopc, val;
#ifdef FKS_REG_LOGGING
printk(KERN_INFO "FKS: ess_dsp_reset 1\n");
@@ -859,77 +706,100 @@ ess_show_mixerregs (devc);
DDB(printk("sb: No response to RESET\n"));
return 0; /* Sorry */
}
- ess_extended (devc);
-
- DEB(printk("sb_dsp_reset() OK\n"));
-
-#ifdef FKS_LOGGING
-printk(KERN_INFO "FKS: dsp_reset 2\n");
-ess_show_mixerregs (devc);
-#endif
- return 1;
-}
+ sb_dsp_command(devc, 0xc6); /* Enable extended mode */
+ if (!(devc->caps & ESSCAP_PNP)) {
+ ess_setmixer (devc, 0x40, 0x03); /* Enable joystick and OPL3 */
-static int ess_irq_bits (int irq)
-{
- switch (irq) {
- case 2:
- case 9:
- return 0;
-
- case 5:
- return 1;
+ 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));
- case 7:
- return 2;
+ if (devc->caps & ESSCAP_IRQ) {
+ ess_setmixer (devc, 0x7f, 0x01 | (val << 1)); /* IRQ config */
+ }
- case 10:
- return 3;
+ 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 */
- default:
- printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq);
- return -1;
+ 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 */
+ }
}
-}
-
-/*
- * Set IRQ configuration register for all ESS models
- */
-static int ess_common_set_irq_hw (sb_devc * devc)
-{
- int irq_bits;
-
- 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;
+ 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 */
}
- 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;
+ 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 */
+ }
- ess_chgmixer (devc, 0x7f, 0x0f, 0x01 | ((irq_bits + 1) << 1));
-}
+ DEB(printk("sb_dsp_reset() OK\n"));
-static int ess_set_irq_hw (sb_devc * devc)
-{
- if (devc->submodel == SUBMDL_ES1887) ess_es1887_set_irq_hw (devc);
+#ifdef FKS_LOGGING
+printk(KERN_INFO "FKS: dsp_reset 2\n");
+ess_show_mixerregs (devc);
+#endif
- return ess_common_set_irq_hw (devc);
+ return 1;
}
#ifdef FKS_TEST
@@ -955,7 +825,7 @@ printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff));
};
#endif
-static unsigned int ess_identify (sb_devc * devc)
+static unsigned int ess_identify (sb_devc * devc, int *control)
{
unsigned int val;
unsigned long flags;
@@ -969,8 +839,15 @@ static unsigned int ess_identify (sb_devc * devc)
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;
}
@@ -997,7 +874,6 @@ 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];
@@ -1005,6 +881,7 @@ 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 */
@@ -1056,10 +933,10 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
case ESSTYPE_LIKE20:
break;
case 688:
- submodel = 0x00;
+ submodel = SUBMDL_ES688;
break;
case 1688:
- submodel = 0x08;
+ submodel = SUBMDL_ES1688;
break;
case 1868:
submodel = SUBMDL_ES1868;
@@ -1070,6 +947,12 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
case 1788:
submodel = SUBMDL_ES1788;
break;
+ case 1878:
+ submodel = SUBMDL_ES1878;
+ break;
+ case 1879:
+ submodel = SUBMDL_ES1879;
+ break;
case 1887:
submodel = SUBMDL_ES1887;
break;
@@ -1102,7 +985,7 @@ FKS_test (devc);
if (chip == NULL) {
int type;
- type = ess_identify (devc);
+ type = ess_identify (devc, &devc->pcibase);
switch (type) {
case 0x1868:
@@ -1117,6 +1000,10 @@ FKS_test (devc);
chip = "ES1878";
devc->submodel = SUBMDL_ES1878;
break;
+ case 0x1879:
+ chip = "ES1879";
+ devc->submodel = SUBMDL_ES1879;
+ break;
default:
if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) {
printk ("ess_init: Unrecognized %04x\n", type);
@@ -1175,130 +1062,72 @@ FKS_test (devc);
strcpy(name, "Jazz16");
}
- 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 */
+ 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;
}
- sb_dsp_reset (devc);
-
- /*
- * This is important! If it's not done, the IRQ probe in sb_dsp_init
- * may fail.
- */
- return ess_set_irq_hw (devc);
-}
-
-static int ess_set_dma_hw(sb_devc * devc)
-{
- unsigned char cfg, dma_bits = 0, dma16_bits;
- int dma;
-
-#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 (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;
}
- if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) {
- printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n");
- return 0;
- }
+ devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */
- if (devc->duplex) {
- dma = devc->dma16;
- dma16_bits = 0;
+ hw_config->name = name;
+
+ sb_dsp_reset(devc); /* Turn on extended mode */
+
+ ess_setmixer (devc, 0x00, 0x00); /* Reset mixer registers */
- 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 for ES1887 too
- *
+ * Full Duplex. Let's try this too
*/
- 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) {
+ if ((devc->caps & ESSCAP_ES18) && hw_config->dma2 >= 0) {
+ devc->dma16 = hw_config->dma2;
+ if (devc->dma8 != devc->dma16) {
devc->duplex = 1;
}
-
- if (!ess_set_dma_hw (devc)) {
- free_irq(devc->irq, devc);
- return 0;
- }
- return 1;
- } else {
- return -1;
}
+ return 1;
}
/****************************************************************************
@@ -1319,13 +1148,13 @@ int ess_dsp_init (sb_devc *devc, struct address_info *hw_config)
#define ES1688_MIXER_DEVICES \
( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV )
-#define ES1887_RECORDING_DEVICES \
+#define ES_NEW_RECORDING_DEVICES \
( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH)
-#define ES1887_MIXER_DEVICES \
+#define ES_NEW_MIXER_DEVICES \
( ES1688_MIXER_DEVICES )
/*
- * Mixer registers of ES1887
+ * Mixer registers of ES18xx with new capabilities
*
* These registers specifically take care of recording levels. To make the
* mapping from playback devices to recording devices every recording
@@ -1455,11 +1284,11 @@ MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
};
/*
- * 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
+ * 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
* Audio 2 for playback.
*/
-static mixer_tab es1887_mix = {
+static mixer_tab es_new_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),
@@ -1493,16 +1322,6 @@ 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
@@ -1533,15 +1352,13 @@ 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);
- udelay(20);
- outb(((unsigned char) (value & 0xff)), MIXER_DATA);
- udelay(20);
- };
+ outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
+
+ udelay(20);
+ outb(((unsigned char) (value & 0xff)), MIXER_DATA);
+ udelay(20);
+
restore_flags(flags);
}
@@ -1553,15 +1370,12 @@ unsigned int ess_getmixer (sb_devc * devc, unsigned int port)
save_flags(flags);
cli();
- if (port >= 0xa0) {
- val = ess_read (devc, port);
- } else {
- outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
+ outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
+
+ udelay(20);
+ val = inb(MIXER_DATA);
+ udelay(20);
- udelay(20);
- val = inb(MIXER_DATA);
- udelay(20);
- }
restore_flags(flags);
return val;
@@ -1585,23 +1399,21 @@ void ess_mixer_init (sb_devc * devc)
devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
/*
- * Take care of ES1887 specifics...
+ * Take care of new ES's specifics...
*/
- switch (devc->submodel) {
- case SUBMDL_ES1887:
- devc->supported_devices = ES1887_MIXER_DEVICES;
- devc->supported_rec_devices = ES1887_RECORDING_DEVICES;
+ if (devc->caps & ESSCAP_NEW) {
+ devc->supported_devices = ES_NEW_MIXER_DEVICES;
+ devc->supported_rec_devices = ES_NEW_RECORDING_DEVICES;
#ifdef FKS_LOGGING
printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
#endif
if (devc->duplex) {
- devc->iomap = &es1887_mix;
+ devc->iomap = &es_new_mix;
} else {
devc->iomap = &es_rec_mix;
}
- break;
- default:
- if (devc->submodel < 8) {
+ } else {
+ if (devc->submodel == SUBMDL_ES688) {
devc->supported_devices = ES688_MIXER_DEVICES;
devc->supported_rec_devices = ES688_RECORDING_DEVICES;
devc->iomap = &es688_mix;
@@ -1612,10 +1424,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->submodel < 0x10) {
- devc->iomap = &es1688_mix;
- } else {
+ if (devc->caps & ESSCAP_ES18) {
devc->iomap = &es1688later_mix;
+ } else {
+ devc->iomap = &es1688_mix;
}
}
}
@@ -1627,9 +1439,15 @@ 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 (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) {
+ if ((devc->caps & ESSCAP_NEW) && (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);
}
@@ -1675,7 +1493,6 @@ 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);
@@ -1688,7 +1505,7 @@ int ess_set_recmask(sb_devc * devc, int *mask)
{
/* This applies to ESS chips with record mixers only! */
- if (ess_has_rec_mixer (devc->submodel)) {
+ if (devc->caps & ESSCAP_NEW) {
*mask = es_rec_set_recmask (devc, *mask);
return 1; /* Applied */
} else {
@@ -1704,18 +1521,7 @@ int ess_mixer_reset (sb_devc * devc)
/*
* Separate actions for ESS chips with a record mixer:
*/
- 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;
- };
+ if (devc->caps & ESSCAP_NEW) {
/*
* Call set_recmask for proper initialization
*/
@@ -1735,50 +1541,80 @@ 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)
{
- unsigned char cfg, tmp;
+ int val;
- 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 */
+ if (devc->submodel == SUBMDL_ES688) {
+ return 0; /* ES688 doesn't support MPU401 mode */
}
- tmp = (hw_config->io_base & 0x0f0) >> 4;
- if (tmp > 3) {
- ess_setmixer (devc, 0x40, cfg);
- return 0;
+ if (hw_config->irq < 2) {
+ hw_config->irq = devc->irq;
}
- cfg |= tmp << 3;
-
- tmp = 1; /* MPU enabled without interrupts */
- /* May be shared: if so the value is -ve */
+ 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;
+ }
- 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;
+ 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;
+ }
}
- cfg |= tmp << 5;
- ess_setmixer (devc, 0x40, cfg | 0x03);
+ if (devc->irq == hw_config->irq) /* Shared IRQ */
+ hw_config->irq = -devc->irq;
return 1;
}