summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authornathanw <nathanw@NetBSD.org>1999-03-02 20:36:50 +0000
committernathanw <nathanw@NetBSD.org>1999-03-02 20:36:50 +0000
commit64fffdfef919ceb99b88808879dfd1236ebbc284 (patch)
tree9d30c86b49acf51a9daa4755def1a12663c3d911 /sys/dev
parentcfcb284c098ed015127724370b79935d536663e4 (diff)
Add support for the 1788 AudioDrive chip.
Some minor cleanup; refer to more registers by macros rather than raw hex constants.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/isa/ess.c951
-rw-r--r--sys/dev/isa/essreg.h40
-rw-r--r--sys/dev/isa/essvar.h38
3 files changed, 733 insertions, 296 deletions
diff --git a/sys/dev/isa/ess.c b/sys/dev/isa/ess.c
index d5cbaa5d26c..d2e5db624e0 100644
--- a/sys/dev/isa/ess.c
+++ b/sys/dev/isa/ess.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ess.c,v 1.32 1999/02/22 01:57:33 mycroft Exp $ */
+/* $NetBSD: ess.c,v 1.33 1999/03/02 20:36:50 nathanw Exp $ */
/*
* Copyright 1997
@@ -61,6 +61,7 @@
**
** Heavily modified by Lennart Augustsson and Charles M. Hannum for
** bus_dma, changes to audio interface, and many bug fixes.
+** Modified by Nathan J. Williams for 1788 support.
**--
*/
@@ -109,7 +110,8 @@ unsigned uuu;
int ess_setup_sc __P((struct ess_softc *, int));
int ess_open __P((void *, int));
-void ess_close __P((void *));
+void ess_1788_close __P((void *));
+void ess_1888_close __P((void *));
int ess_getdev __P((void *, struct audio_device *));
int ess_drain __P((void *));
@@ -120,12 +122,18 @@ int ess_set_params __P((void *, int, int, struct audio_params *,
int ess_round_blocksize __P((void *, int));
-int ess_trigger_output __P((void *, void *, void *, int, void (*)(void *),
+int ess_1788_trigger_output __P((void *, void *, void *, int, void (*)(void *),
void *, struct audio_params *));
-int ess_trigger_input __P((void *, void *, void *, int, void (*)(void *),
+int ess_1888_trigger_output __P((void *, void *, void *, int, void (*)(void *),
void *, struct audio_params *));
-int ess_halt_output __P((void *));
-int ess_halt_input __P((void *));
+int ess_1788_trigger_input __P((void *, void *, void *, int, void (*)(void *),
+ void *, struct audio_params *));
+int ess_1888_trigger_input __P((void *, void *, void *, int, void (*)(void *),
+ void *, struct audio_params *));
+int ess_1788_halt_output __P((void *));
+int ess_1888_halt_output __P((void *));
+int ess_1788_halt_input __P((void *));
+int ess_1888_halt_input __P((void *));
int ess_intr_output __P((void *));
int ess_intr_input __P((void *));
@@ -157,6 +165,7 @@ int ess_identify __P((struct ess_softc *));
int ess_reset __P((struct ess_softc *));
void ess_set_gain __P((struct ess_softc *, int, int));
+int ess_set_in_port __P((struct ess_softc *, int));
int ess_set_in_ports __P((struct ess_softc *, int));
u_int ess_srtotc __P((u_int));
u_int ess_srtofc __P((u_int));
@@ -178,7 +187,8 @@ static char *essmodel[] = {
"unsupported",
"1888",
"1887",
- "888"
+ "888",
+ "1788"
};
struct audio_device ess_device = {
@@ -191,9 +201,38 @@ struct audio_device ess_device = {
* Define our interface to the higher level audio driver.
*/
-struct audio_hw_if ess_hw_if = {
+struct audio_hw_if ess_1788_hw_if = {
+ ess_open,
+ ess_1788_close,
+ ess_drain,
+ ess_query_encoding,
+ ess_set_params,
+ ess_round_blocksize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ess_1788_halt_output,
+ ess_1788_halt_input,
+ ess_speaker_ctl,
+ ess_getdev,
+ NULL,
+ ess_set_port,
+ ess_get_port,
+ ess_query_devinfo,
+ ess_malloc,
+ ess_free,
+ ess_round_buffersize,
+ ess_mappage,
+ ess_get_props,
+ ess_1788_trigger_output,
+ ess_1788_trigger_input,
+};
+
+struct audio_hw_if ess_1888_hw_if = {
ess_open,
- ess_close,
+ ess_1888_close,
ess_drain,
ess_query_encoding,
ess_set_params,
@@ -203,8 +242,8 @@ struct audio_hw_if ess_hw_if = {
NULL,
NULL,
NULL,
- ess_halt_output,
- ess_halt_input,
+ ess_1888_halt_output,
+ ess_1888_halt_input,
ess_speaker_ctl,
ess_getdev,
NULL,
@@ -214,10 +253,10 @@ struct audio_hw_if ess_hw_if = {
ess_malloc,
ess_free,
ess_round_buffersize,
- ess_mappage,
+ ess_mappage,
ess_get_props,
- ess_trigger_output,
- ess_trigger_input,
+ ess_1888_trigger_output,
+ ess_1888_trigger_input,
};
#ifdef AUDIO_DEBUG
@@ -243,7 +282,7 @@ ess_printsc(sc)
sc->sc_in.intr, sc->sc_in.arg);
printf("gain:");
- for (i = 0; i < ESS_NDEVS; i++)
+ for (i = 0; i < sc->ndevs; i++)
printf(" %u,%u", sc->gain[i][ESS_LEFT], sc->gain[i][ESS_RIGHT]);
printf("\n");
}
@@ -252,8 +291,13 @@ void
ess_dump_mixer(sc)
struct ess_softc *sc;
{
+ printf("ESS_LEFT_MASTER: mix reg 0x%02x=0x%02x\n",
+ 0x60, ess_read_mix_reg(sc, 0x60));
+ printf("ESS_RIGHT_MASTER: mix reg 0x%02x=0x%02x\n",
+ 0x62, ess_read_mix_reg(sc, 0x62));
+
printf("ESS_DAC_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
- 0x7C, ess_read_mix_reg(sc, 0x7C));
+ 0x14, ess_read_mix_reg(sc, 0x14));
printf("ESS_MIC_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
0x1A, ess_read_mix_reg(sc, 0x1A));
printf("ESS_LINE_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
@@ -401,7 +445,7 @@ ess_config_irq(sc)
DPRINTFN(2,("ess_config_irq\n"));
- if (sc->sc_in.irq != sc->sc_out.irq) {
+ if (sc->sc_in.irq != sc->sc_out.irq || sc->sc_model == ESS_1788) {
/* Configure Audio 1 (record) for the appropriate IRQ line. */
v = ESS_IRQ_CTRL_MASK | ESS_IRQ_CTRL_EXT; /* All intrs on */
switch(sc->sc_in.irq) {
@@ -425,11 +469,13 @@ ess_config_irq(sc)
#endif
}
ess_write_x_reg(sc, ESS_XCMD_IRQ_CTRL, v);
- /* irq2 is hardwired to 15 in this mode */
- ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_IRQ2_ENABLE);
- /* Use old method. */
- ess_write_mix_reg(sc, ESS_MREG_INTR_ST, ESS_IS_ES1888);
+ if (sc->sc_model != ESS_1788) {
+ /* irq2 is hardwired to 15 in this mode */
+ ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
+ ESS_AUDIO2_CTRL2_IRQ2_ENABLE);
+ /* Use old method. */
+ ess_write_mix_reg(sc, ESS_MREG_INTR_ST, ESS_IS_ES1888);
+ }
} else {
/* Use new method, both interrupts are the same. */
v = ESS_IS_SELECT_IRQ; /* enable intrs */
@@ -492,32 +538,34 @@ ess_config_drq(sc)
/* Set DRQ1 */
ess_write_x_reg(sc, ESS_XCMD_DRQ_CTRL, v);
- /* Configure DRQ2 */
- v = ESS_AUDIO2_CTRL3_DRQ_PD;
- switch(sc->sc_out.drq) {
- case 0:
- v |= ESS_AUDIO2_CTRL3_DRQA;
- break;
- case 1:
- v |= ESS_AUDIO2_CTRL3_DRQB;
- break;
- case 3:
- v |= ESS_AUDIO2_CTRL3_DRQC;
- break;
- case 5:
- v |= ESS_AUDIO2_CTRL3_DRQC;
- break;
+ if (sc->sc_model != ESS_1788) {
+ /* Configure DRQ2 */
+ v = ESS_AUDIO2_CTRL3_DRQ_PD;
+ switch(sc->sc_out.drq) {
+ case 0:
+ v |= ESS_AUDIO2_CTRL3_DRQA;
+ break;
+ case 1:
+ v |= ESS_AUDIO2_CTRL3_DRQB;
+ break;
+ case 3:
+ v |= ESS_AUDIO2_CTRL3_DRQC;
+ break;
+ case 5:
+ v |= ESS_AUDIO2_CTRL3_DRQD;
+ break;
#ifdef DIAGNOSTIC
- default:
- printf("ess_config_drq: configured dma chan %d not supported for Audio 2\n",
- sc->sc_out.drq);
- return;
+ default:
+ printf("ess_config_drq: configured dma chan %d not supported for Audio 2\n",
+ sc->sc_out.drq);
+ return;
#endif
+ }
+ ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL3, v);
+ /* Enable DMA 2 */
+ ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
+ ESS_AUDIO2_CTRL2_DMA_ENABLE);
}
- ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL3, v);
- /* Enable DMA 2 */
- ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_DMA_ENABLE);
}
/*
@@ -583,12 +631,12 @@ ess_identify(sc)
* 2. Verify we can change bit 2 in mixer register 0x64. This
* should be possible on all supported chips.
*/
- reg1 = ess_read_mix_reg(sc, 0x64);
+ reg1 = ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL);
reg2 = reg1 ^ 0x04; /* toggle bit 2 */
- ess_write_mix_reg(sc, 0x64, reg2);
+ ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg2);
- if (ess_read_mix_reg(sc, 0x64) != reg2) {
+ if (ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL) != reg2) {
printf("ess: Hardware error (unable to toggle bit 2 of mixer register 0x64)\n");
return 1;
}
@@ -596,13 +644,13 @@ ess_identify(sc)
/*
* Restore the original value of mixer register 0x64.
*/
- ess_write_mix_reg(sc, 0x64, reg1);
+ ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg1);
/*
* 3. Verify we can change the value of mixer register
* ESS_MREG_SAMPLE_RATE.
- * This should be possible on all supported chips.
+ * This is possible on the 1888/1887/888, but not on the 1788.
* It is not necessary to restore the value of this mixer register.
*/
reg1 = ess_read_mix_reg(sc, ESS_MREG_SAMPLE_RATE);
@@ -611,60 +659,67 @@ ess_identify(sc)
ess_write_mix_reg(sc, ESS_MREG_SAMPLE_RATE, reg2);
if (ess_read_mix_reg(sc, ESS_MREG_SAMPLE_RATE) != reg2) {
- printf("ess: Hardware error (unable to change mixer register 0x70)\n");
- return 1;
- }
-
- /*
- * 4. Determine if we can change bit 5 in mixer register 0x64.
- * This determines whether we have an ES1887:
- *
- * - can change indicates ES1887
- * - can't change indicates ES1888 or ES888
- */
- reg1 = ess_read_mix_reg(sc, 0x64);
- reg2 = reg1 ^ 0x20; /* toggle bit 5 */
-
- ess_write_mix_reg(sc, 0x64, reg2);
-
- if (ess_read_mix_reg(sc, 0x64) == reg2) {
- sc->sc_model = ESS_1887;
-
- /*
- * Restore the original value of mixer register 0x64.
- */
- ess_write_mix_reg(sc, 0x64, reg1);
+ /* If we got this far before failing, it's a 1788. */
+ sc->sc_model = ESS_1788;
} else {
/*
- * 5. Determine if we can change the value of mixer
- * register 0x69 independently of mixer register
- * 0x68. This determines which chip we have:
+ * 4. Determine if we can change bit 5 in mixer register 0x64.
+ * This determines whether we have an ES1887:
*
- * - can modify idependently indicates ES888
- * - register 0x69 is an alias of 0x68 indicates ES1888
+ * - can change indicates ES1887
+ * - can't change indicates ES1888 or ES888
*/
- reg1 = ess_read_mix_reg(sc, 0x68);
- reg2 = ess_read_mix_reg(sc, 0x69);
- reg3 = reg2 ^ 0xff; /* toggle all bits */
-
- /*
- * Write different values to each register.
- */
- ess_write_mix_reg(sc, 0x68, reg2);
- ess_write_mix_reg(sc, 0x69, reg3);
-
- if (ess_read_mix_reg(sc, 0x68) == reg2)
- sc->sc_model = ESS_888;
- else
- sc->sc_model = ESS_1888;
+ reg1 = ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL);
+ reg2 = reg1 ^ 0x20; /* toggle bit 5 */
+
+ ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg2);
+
+ if (ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL) == reg2) {
+ sc->sc_model = ESS_1887;
+
+ /*
+ * Restore the original value of mixer register 0x64.
+ */
+ ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg1);
+ } else {
+ /*
+ * 5. Determine if we can change the value of mixer
+ * register 0x69 independently of mixer register
+ * 0x68. This determines which chip we have:
+ *
+ * - can modify idependently indicates ES888
+ * - register 0x69 is an alias of 0x68 indicates ES1888
+ */
+ reg1 = ess_read_mix_reg(sc, 0x68);
+ reg2 = ess_read_mix_reg(sc, 0x69);
+ reg3 = reg2 ^ 0xff; /* toggle all bits */
+
+ /*
+ * Write different values to each register.
+ */
+ ess_write_mix_reg(sc, 0x68, reg2);
+ ess_write_mix_reg(sc, 0x69, reg3);
+
+ if (ess_read_mix_reg(sc, 0x68) == reg2)
+ sc->sc_model = ESS_888;
+ else
+ sc->sc_model = ESS_1888;
- /*
- * Restore the original value of the registers.
- */
- ess_write_mix_reg(sc, 0x68, reg1);
- ess_write_mix_reg(sc, 0x69, reg2);
+ /*
+ * Restore the original value of the registers.
+ */
+ ess_write_mix_reg(sc, 0x68, reg1);
+ ess_write_mix_reg(sc, 0x69, reg2);
+ }
}
+ if (sc->sc_model != ESS_UNSUPPORTED) {
+ if (sc->sc_model == ESS_1788)
+ sc->ndevs = ESS_1788_NDEVS;
+ else
+ sc->ndevs = ESS_1888_NDEVS;
+ }
+
return 0;
}
@@ -718,46 +773,58 @@ essmatch(sc)
printf("ess: record dma chan %d invalid\n", sc->sc_in.drq);
return (0);
}
- if (!ESS_DRQ2_VALID(sc->sc_out.drq, sc->sc_model)) {
- printf("ess: play dma chan %d invalid\n", sc->sc_out.drq);
- return (0);
- }
- if (sc->sc_in.drq == sc->sc_out.drq) {
- printf("ess: play and record dma chan both %d\n",
- sc->sc_in.drq);
- return (0);
- }
-
- if (sc->sc_model == ESS_1887) {
- /*
- * Either use the 1887 interrupt mode with all interrupts
- * mapped to the same irq, or use the 1888 method with
- * irq fixed at 15.
- */
- if (sc->sc_in.irq == sc->sc_out.irq) {
- if (!ESS_IRQ12_VALID(sc->sc_in.irq)) {
- printf("ess: irq %d invalid\n", sc->sc_in.irq);
- return (0);
- }
- goto irq_not1888;
+ /* 1788 only has one DMA channel. */
+ if (sc->sc_model != ESS_1788) {
+ if (!ESS_DRQ2_VALID(sc->sc_out.drq, sc->sc_model)) {
+ printf("ess: play dma chan %d invalid\n", sc->sc_out.drq);
+ return (0);
}
- } else {
- /* Must use separate interrupts */
- if (sc->sc_in.irq == sc->sc_out.irq) {
- printf("ess: play and record irq both %d\n",
- sc->sc_in.irq);
+ if (sc->sc_in.drq == sc->sc_out.drq) {
+ printf("ess: play and record dma chan both %d\n",
+ sc->sc_in.drq);
return (0);
}
+
+ if (sc->sc_model == ESS_1887) {
+ /*
+ * Either use the 1887 interrupt mode with all interrupts
+ * mapped to the same irq, or use the 1888 method with
+ * irq fixed at 15.
+ */
+ if (sc->sc_in.irq == sc->sc_out.irq) {
+ if (!ESS_IRQ12_VALID(sc->sc_in.irq)) {
+ printf("ess: irq %d invalid\n", sc->sc_in.irq);
+ return (0);
+ }
+ goto irq_not1888;
+ }
+ } else {
+ /* Must use separate interrupts */
+ if (sc->sc_in.irq == sc->sc_out.irq) {
+ printf("ess: play and record irq both %d\n",
+ sc->sc_in.irq);
+ return (0);
+ }
+ }
}
- /* Check that requested IRQ lines are valid and different. */
- if (!ESS_IRQ1_VALID(sc->sc_in.irq)) {
- printf("ess: record irq %d invalid\n", sc->sc_in.irq);
- return (0);
- }
- if (!ESS_IRQ2_VALID(sc->sc_out.irq)) {
- printf("ess: play irq %d invalid\n", sc->sc_out.irq);
+ if (sc->sc_model == ESS_1788) {
+ /* Check that requested IRQ line is valid.
+ */
+ if (!ESS_IRQ1_VALID(sc->sc_in.irq)) {
+ printf("ess: irq %d invalid\n", sc->sc_in.irq);
return (0);
+ }
+ } else {
+ /* Check that requested IRQ lines are valid. */
+ if (!ESS_IRQ1_VALID(sc->sc_in.irq)) {
+ printf("ess: record irq %d invalid\n", sc->sc_in.irq);
+ return (0);
+ }
+ if (!ESS_IRQ2_VALID(sc->sc_out.irq)) {
+ printf("ess: play irq %d invalid\n", sc->sc_out.irq);
+ return (0);
+ }
}
irq_not1888:
@@ -765,6 +832,7 @@ essmatch(sc)
if (!isa_drq_isfree(sc->sc_ic, sc->sc_in.drq) ||
!isa_drq_isfree(sc->sc_ic, sc->sc_out.drq))
return (0);
+
/* XXX should we check IRQs as well? */
return (1);
@@ -788,6 +856,12 @@ essattach(sc)
printf("%s: setup failed\n", sc->sc_dev.dv_xname);
return;
}
+
+ /* 1788 only uses one IRQ and DRQ */
+ if (sc->sc_model == ESS_1788) {
+ sc->sc_out.irq = sc->sc_in.irq;
+ sc->sc_out.drq = sc->sc_in.drq;
+ }
sc->sc_out.ih = isa_intr_establish(sc->sc_ic, sc->sc_out.irq,
sc->sc_out.ist, IPL_AUDIO,
@@ -798,16 +872,19 @@ essattach(sc)
/* Create our DMA maps. */
if (isa_dmamap_create(sc->sc_ic, sc->sc_in.drq,
- MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
+ MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
printf("%s: can't create map for drq %d\n",
- sc->sc_dev.dv_xname, sc->sc_in.drq);
+ sc->sc_dev.dv_xname, sc->sc_in.drq);
return;
}
- if (isa_dmamap_create(sc->sc_ic, sc->sc_out.drq,
- MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
- printf("%s: can't create map for drq %d\n",
- sc->sc_dev.dv_xname, sc->sc_out.drq);
- return;
+
+ if (sc->sc_model != ESS_1788) {
+ if (isa_dmamap_create(sc->sc_ic, sc->sc_out.drq,
+ MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
+ printf("%s: can't create map for drq %d\n",
+ sc->sc_dev.dv_xname, sc->sc_out.drq);
+ return;
+ }
}
printf(" ESS Technology ES%s [version 0x%04x]\n",
@@ -824,29 +901,40 @@ essattach(sc)
/* Do a hardware reset on the mixer. */
ess_write_mix_reg(sc, ESS_MIX_RESET, ESS_MIX_RESET);
- /*
- * Set volume of Audio 1 to zero and disable Audio 1 DAC input
- * to playback mixer, since playback is always through Audio 2.
- */
- ess_write_mix_reg(sc, 0x14, 0);
- ess_wdsp(sc, ESS_ACMD_DISABLE_SPKR);
+ if (sc->sc_model != ESS_1788) {
+ /*
+ * Set volume of Audio 1 to zero and disable Audio 1 DAC input
+ * to playback mixer, since playback is always through Audio 2
+ * on the 188x.
+ */
+ ess_write_mix_reg(sc, ESS_MREG_VOLUME_VOICE, 0);
+ ess_wdsp(sc, ESS_ACMD_DISABLE_SPKR);
+ }
- /*
- * Set hardware record source to use output of the record
- * mixer. We do the selection of record source in software by
- * setting the gain of the unused sources to zero. (See
- * ess_set_in_ports.)
- */
- ess_set_mreg_bits(sc, 0x1c, 0x07);
- ess_clear_mreg_bits(sc, 0x7a, 0x10);
- ess_set_mreg_bits(sc, 0x7a, 0x08);
+ if (sc->sc_model == ESS_1788) {
+ /*
+ * Set record source to mic.
+ */
+ ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ESS_SOURCE_MIC);
+ sc->in_port = ESS_SOURCE_MIC;
+ } else {
+ /*
+ * Set hardware record source to use output of the record
+ * mixer. We do the selection of record source in software by
+ * setting the gain of the unused sources to zero. (See
+ * ess_set_in_ports.)
+ */
+ ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ESS_SOURCE_MIXER);
+ ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2, 0x10);
+ ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2, 0x08);
+ }
/*
* Set gain on each mixer device to a sensible value.
* Devices not normally used are turned off, and other devices
* are set to 50% volume.
*/
- for (i = 0; i < ESS_NDEVS; i++) {
+ for (i = 0; i < sc->ndevs; i++) {
switch(i) {
case ESS_MIC_PLAY_VOL:
case ESS_LINE_PLAY_VOL:
@@ -876,7 +964,10 @@ essattach(sc)
sprintf(ess_device.name, "ES%s", essmodel[sc->sc_model]);
sprintf(ess_device.version, "0x%04x", sc->sc_version);
- audio_attach_mi(&ess_hw_if, sc, &sc->sc_dev);
+ if (sc->sc_model == ESS_1788)
+ audio_attach_mi(&ess_1788_hw_if, sc, &sc->sc_dev);
+ else
+ audio_attach_mi(&ess_1888_hw_if, sc, &sc->sc_dev);
arg.type = AUDIODEV_TYPE_OPL;
arg.hwif = 0;
@@ -915,19 +1006,36 @@ ess_open(addr, flags)
}
void
-ess_close(addr)
+ess_1788_close(addr)
void *addr;
{
struct ess_softc *sc = addr;
- DPRINTF(("ess_close: sc=%p\n", sc));
+ DPRINTF(("ess_1788_close: sc=%p\n", sc));
ess_speaker_off(sc);
sc->spkr_state = SPKR_OFF;
+ ess_1788_halt_output(sc);
+ ess_1788_halt_input(sc);
+ sc->sc_in.intr = 0;
+ sc->sc_out.intr = 0;
+ sc->sc_open = 0;
- ess_halt_output(sc);
- ess_halt_input(sc);
+ DPRINTF(("ess_close: closed\n"));
+}
+void
+ess_1888_close(addr)
+ void *addr;
+{
+ struct ess_softc *sc = addr;
+
+ DPRINTF(("ess_close: sc=%p\n", sc));
+
+ ess_speaker_off(sc);
+ sc->spkr_state = SPKR_OFF;
+ ess_1888_halt_output(sc);
+ ess_1888_halt_input(sc);
sc->sc_in.intr = 0;
sc->sc_out.intr = 0;
sc->sc_open = 0;
@@ -937,7 +1045,7 @@ ess_close(addr)
/*
* Wait for FIFO to drain, and analog section to settle.
- * XXX should check FIFO full bit.
+ * XXX should check FIFO empty bit.
*/
int
ess_drain(addr)
@@ -1009,7 +1117,7 @@ ess_query_encoding(addr, fp)
fp->precision = 8;
fp->flags = 0;
return (0);
- case 4:
+ case 4:
strcpy(fp->name, AudioEslinear_le);
fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
fp->precision = 16;
@@ -1119,8 +1227,10 @@ ess_set_params(addr, setmode, usemode, play, rec)
else
rate = play->sample_rate;
- ess_write_mix_reg(sc, ESS_MREG_SAMPLE_RATE, ess_srtotc(rate));
- ess_write_mix_reg(sc, ESS_MREG_FILTER_CLOCK, ess_srtofc(rate));
+ if (sc->sc_model != ESS_1788) {
+ ess_write_mix_reg(sc, ESS_MREG_SAMPLE_RATE, ess_srtotc(rate));
+ ess_write_mix_reg(sc, ESS_MREG_FILTER_CLOCK, ess_srtofc(rate));
+ }
ess_write_x_reg(sc, ESS_XCMD_SAMPLE_RATE, ess_srtotc(rate));
ess_write_x_reg(sc, ESS_XCMD_FILTER_CLOCK, ess_srtofc(rate));
@@ -1129,7 +1239,88 @@ ess_set_params(addr, setmode, usemode, play, rec)
}
int
-ess_trigger_output(addr, start, end, blksize, intr, arg, param)
+ess_1788_trigger_output(addr, start, end, blksize, intr, arg, param)
+ void *addr;
+ void *start, *end;
+ int blksize;
+ void (*intr) __P((void *));
+ void *arg;
+ struct audio_params *param;
+{
+ struct ess_softc *sc = addr;
+ int val;
+
+ DPRINTFN(1, ("ess_1788_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
+ addr, start, end, blksize, intr, arg));
+
+#ifdef DIAGNOSTIC
+ if (param->channels == 2 && (blksize & 1)) {
+ DPRINTF(("stereo playback odd bytes (%d)\n", blksize));
+ return EIO;
+ }
+ if (sc->sc_out.active)
+ panic("ess_1788_trigger_output: already running");
+#endif
+ sc->sc_out.active = 1;
+
+ sc->sc_out.intr = intr;
+ sc->sc_out.arg = arg;
+
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2,
+ ESS_AUDIO1_CTRL2_AUTO_INIT);
+ ess_write_x_reg(sc, ESS_XCMD_DEMAND_CTRL, ESS_DEMAND_CTRL_DEMAND_4);
+
+ val = 0x90;
+ if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
+ param->encoding == AUDIO_ENCODING_SLINEAR_LE) {
+ ess_write_x_reg(sc, ESS_1788_XCMD_AUDIO_CTRL0, ESS_CTRL0_SIGNED);
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, 0x71);
+ val |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
+ } else {
+ ess_write_x_reg(sc, ESS_1788_XCMD_AUDIO_CTRL0, ESS_CTRL0_UNSIGNED);
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, 0x51);
+ }
+
+ if (param->precision * param->factor == 16)
+ val |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
+
+ if (param->channels == 2) {
+ ess_set_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_STEREO);
+ ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_MONO);
+ val |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
+ } else {
+ ess_set_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_MONO);
+ ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_STEREO);
+ val |= ESS_AUDIO1_CTRL1_FIFO_MONO;
+ }
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, val);
+
+ isa_dmastart(sc->sc_ic, sc->sc_out.drq, start,
+ (char *)end - (char *)start, NULL,
+ DMAMODE_WRITE | DMAMODE_LOOP,
+ BUS_DMA_NOWAIT);
+
+ /* Program transfer count registers with 2's complement of count. */
+ blksize = -blksize;
+ ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, blksize);
+ ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, blksize >> 8);
+
+ /* Enable audio */
+ ess_wdsp(sc, ESS_ACMD_ENABLE_SPKR);
+
+ /* Start auto-init DMA */
+ ess_set_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
+ ESS_AUDIO1_CTRL2_FIFO_ENABLE);
+
+ return (0);
+}
+
+int
+ess_1888_trigger_output(addr, start, end, blksize, intr, arg, param)
void *addr;
void *start, *end;
int blksize;
@@ -1140,7 +1331,7 @@ ess_trigger_output(addr, start, end, blksize, intr, arg, param)
struct ess_softc *sc = addr;
DPRINTFN(1, ("ess_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
- addr, start, end, blksize, intr, arg));
+ addr, start, end, blksize, intr, arg));
#ifdef DIAGNOSTIC
if (param->channels == 2 && (blksize & 1)) {
@@ -1157,29 +1348,29 @@ ess_trigger_output(addr, start, end, blksize, intr, arg, param)
if (param->precision * param->factor == 16)
ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_FIFO_SIZE);
+ ESS_AUDIO2_CTRL2_FIFO_SIZE);
else
ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_FIFO_SIZE);
+ ESS_AUDIO2_CTRL2_FIFO_SIZE);
if (param->channels == 2)
ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_CHANNELS);
+ ESS_AUDIO2_CTRL2_CHANNELS);
else
ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_CHANNELS);
+ ESS_AUDIO2_CTRL2_CHANNELS);
if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
- param->encoding == AUDIO_ENCODING_SLINEAR_LE)
+ param->encoding == AUDIO_ENCODING_SLINEAR_LE)
ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_FIFO_SIGNED);
+ ESS_AUDIO2_CTRL2_FIFO_SIGNED);
else
ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_FIFO_SIGNED);
+ ESS_AUDIO2_CTRL2_FIFO_SIGNED);
isa_dmastart(sc->sc_ic, sc->sc_out.drq, start,
- (char *)end - (char *)start, NULL,
- DMAMODE_WRITE | DMAMODE_LOOPDEMAND, BUS_DMA_NOWAIT);
+ (char *)end - (char *)start, NULL,
+ DMAMODE_WRITE | DMAMODE_LOOPDEMAND, BUS_DMA_NOWAIT);
if (IS16BITDRQ(sc->sc_out.drq))
blksize >>= 1; /* use word count for 16 bit DMA */
@@ -1189,28 +1380,27 @@ ess_trigger_output(addr, start, end, blksize, intr, arg, param)
ess_write_mix_reg(sc, ESS_MREG_XFER_COUNTHI, blksize >> 8);
if (IS16BITDRQ(sc->sc_out.drq))
- ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
- ESS_AUDIO2_CTRL1_XFER_SIZE);
+ ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
+ ESS_AUDIO2_CTRL1_XFER_SIZE);
else
- ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
- ESS_AUDIO2_CTRL1_XFER_SIZE);
+ ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
+ ESS_AUDIO2_CTRL1_XFER_SIZE);
/* Use 8 bytes per output DMA. */
ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
- ESS_AUDIO2_CTRL1_DEMAND_8);
+ ESS_AUDIO2_CTRL1_DEMAND_8);
/* Start auto-init DMA */
ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
- ESS_AUDIO2_CTRL1_DAC_ENABLE |
- ESS_AUDIO2_CTRL1_FIFO_ENABLE |
- ESS_AUDIO2_CTRL1_AUTO_INIT);
-
+ ESS_AUDIO2_CTRL1_DAC_ENABLE |
+ ESS_AUDIO2_CTRL1_FIFO_ENABLE |
+ ESS_AUDIO2_CTRL1_AUTO_INIT);
return (0);
}
int
-ess_trigger_input(addr, start, end, blksize, intr, arg, param)
+ess_1788_trigger_input(addr, start, end, blksize, intr, arg, param)
void *addr;
void *start, *end;
int blksize;
@@ -1219,9 +1409,10 @@ ess_trigger_input(addr, start, end, blksize, intr, arg, param)
struct audio_params *param;
{
struct ess_softc *sc = addr;
+ int val;
- DPRINTFN(1, ("ess_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
- addr, start, end, blksize, intr, arg));
+ DPRINTFN(1, ("ess_1788_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
+ addr, start, end, blksize, intr, arg));
#ifdef DIAGNOSTIC
if (param->channels == 2 && (blksize & 1)) {
@@ -1235,43 +1426,120 @@ ess_trigger_input(addr, start, end, blksize, intr, arg, param)
sc->sc_in.intr = intr;
sc->sc_in.arg = arg;
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2,
+ ESS_AUDIO1_CTRL2_AUTO_INIT |
+ ESS_AUDIO1_CTRL2_DMA_READ |
+ ESS_AUDIO1_CTRL2_ADC_ENABLE);
+ ess_write_x_reg(sc, ESS_XCMD_DEMAND_CTRL, ESS_DEMAND_CTRL_DEMAND_4);
+
+ val = 0x90;
+ if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
+ param->encoding == AUDIO_ENCODING_SLINEAR_LE) {
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, 0x71);
+ val |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
+ } else {
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, 0x51);
+ }
+
+ if (param->precision * param->factor == 16)
+ val |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
+
+ if (param->channels == 2) {
+ ess_set_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_STEREO);
+ ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_MONO);
+ val |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
+ } else {
+ ess_set_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_MONO);
+ ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
+ ESS_AUDIO_CTRL_STEREO);
+ val |= ESS_AUDIO1_CTRL1_FIFO_MONO;
+ }
+ ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, val);
+
+ isa_dmastart(sc->sc_ic, sc->sc_in.drq, start,
+ (char *)end - (char *)start, NULL,
+ DMAMODE_READ | DMAMODE_LOOP,
+ BUS_DMA_NOWAIT);
+
+ /* Program transfer count registers with 2's complement of count. */
+ blksize = -blksize;
+ ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, blksize);
+ ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, blksize >> 8);
+
+ /* Start auto-init DMA */
+ ess_set_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
+ ESS_AUDIO1_CTRL2_FIFO_ENABLE);
+
+ return (0);
+
+}
+
+int
+ess_1888_trigger_input(addr, start, end, blksize, intr, arg, param)
+ void *addr;
+ void *start, *end;
+ int blksize;
+ void (*intr) __P((void *));
+ void *arg;
+ struct audio_params *param;
+{
+ struct ess_softc *sc = addr;
+
+ DPRINTFN(1, ("ess_1888_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
+ addr, start, end, blksize, intr, arg));
+
+#ifdef DIAGNOSTIC
+ if (param->channels == 2 && (blksize & 1)) {
+ DPRINTF(("stereo record odd bytes (%d)\n", blksize));
+ return EIO;
+ }
+ if (sc->sc_in.active)
+ panic("ess_1888_trigger_input: already running");
+#endif
+ sc->sc_in.active = 1;
+
+ sc->sc_in.intr = intr;
+ sc->sc_in.arg = arg;
if (param->precision * param->factor == 16)
ess_set_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL1,
- ESS_AUDIO1_CTRL1_FIFO_SIZE);
+ ESS_AUDIO1_CTRL1_FIFO_SIZE);
else
ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL1,
- ESS_AUDIO1_CTRL1_FIFO_SIZE);
+ ESS_AUDIO1_CTRL1_FIFO_SIZE);
if (param->channels == 2) {
ess_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL,
- (ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL) |
- ESS_AUDIO_CTRL_STEREO) &~ ESS_AUDIO_CTRL_MONO);
+ (ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL) |
+ ESS_AUDIO_CTRL_STEREO) &~ ESS_AUDIO_CTRL_MONO);
ess_set_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL1,
- ESS_AUDIO1_CTRL1_FIFO_STEREO);
+ ESS_AUDIO1_CTRL1_FIFO_STEREO);
} else {
ess_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL,
- (ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL) |
- ESS_AUDIO_CTRL_MONO) &~ ESS_AUDIO_CTRL_STEREO);
+ (ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL) |
+ ESS_AUDIO_CTRL_MONO) &~ ESS_AUDIO_CTRL_STEREO);
ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL1,
- ESS_AUDIO1_CTRL1_FIFO_STEREO);
+ ESS_AUDIO1_CTRL1_FIFO_STEREO);
}
if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
- param->encoding == AUDIO_ENCODING_SLINEAR_LE)
+ param->encoding == AUDIO_ENCODING_SLINEAR_LE)
ess_set_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL1,
- ESS_AUDIO1_CTRL1_FIFO_SIGNED);
+ ESS_AUDIO1_CTRL1_FIFO_SIGNED);
else
ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL1,
- ESS_AUDIO1_CTRL1_FIFO_SIGNED);
+ ESS_AUDIO1_CTRL1_FIFO_SIGNED);
/* REVISIT: Hack to enable Audio1 FIFO connection to CODEC. */
ess_set_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL1,
- ESS_AUDIO1_CTRL1_FIFO_CONNECT);
+ ESS_AUDIO1_CTRL1_FIFO_CONNECT);
isa_dmastart(sc->sc_ic, sc->sc_in.drq, start,
- (char *)end - (char *)start, NULL,
- DMAMODE_READ | DMAMODE_LOOPDEMAND, BUS_DMA_NOWAIT);
+ (char *)end - (char *)start, NULL,
+ DMAMODE_READ | DMAMODE_LOOPDEMAND, BUS_DMA_NOWAIT);
if (IS16BITDRQ(sc->sc_in.drq))
blksize >>= 1; /* use word count for 16 bit DMA */
@@ -1282,7 +1550,7 @@ ess_trigger_input(addr, start, end, blksize, intr, arg, param)
/* Use 4 bytes per input DMA. */
ess_set_xreg_bits(sc, ESS_XCMD_DEMAND_CTRL,
- ESS_DEMAND_CTRL_DEMAND_4);
+ ESS_DEMAND_CTRL_DEMAND_4);
/* Start auto-init DMA */
ess_set_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
@@ -1295,14 +1563,30 @@ ess_trigger_input(addr, start, end, blksize, intr, arg, param)
}
-int
-ess_halt_output(addr)
+int ess_1788_halt_output(addr)
void *addr;
{
struct ess_softc *sc = addr;
- DPRINTF(("ess_halt_output: sc=%p\n", sc));
+ DPRINTF(("ess_1788_halt_output: sc=%p\n", sc));
+ if (sc->sc_out.active) {
+ ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
+ ESS_AUDIO1_CTRL2_FIFO_ENABLE);
+ ess_wdsp(sc, ESS_ACMD_DISABLE_SPKR);
+ isa_dmaabort(sc->sc_ic, sc->sc_out.drq);
+ sc->sc_out.active = 0;
+ }
+ return (0);
+}
+
+int
+ess_1888_halt_output(addr)
+ void *addr;
+{
+ struct ess_softc *sc = addr;
+
+ DPRINTF(("ess_1888_halt_output: sc=%p\n", sc));
if (sc->sc_out.active) {
ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
ESS_AUDIO2_CTRL1_DAC_ENABLE |
@@ -1315,7 +1599,26 @@ ess_halt_output(addr)
}
int
-ess_halt_input(addr)
+ess_1788_halt_input(addr)
+ void *addr;
+{
+ struct ess_softc *sc = addr;
+
+ DPRINTF(("ess_halt_input: sc=%p\n", sc));
+
+ if (sc->sc_in.active) {
+ ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
+ ESS_AUDIO2_CTRL1_FIFO_ENABLE);
+ isa_dmaabort(sc->sc_ic, sc->sc_in.drq);
+ sc->sc_in.active = 0;
+ }
+
+ return (0);
+}
+
+
+int
+ess_1888_halt_input(addr)
void *addr;
{
struct ess_softc *sc = addr;
@@ -1338,19 +1641,29 @@ ess_intr_output(arg)
void *arg;
{
struct ess_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int irq;
DPRINTFN(1,("ess_intr_output: intr=%p\n", sc->sc_out.intr));
- /* clear interrupt on Audio channel 2 */
- ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
- ESS_AUDIO2_CTRL2_IRQ_LATCH);
+ irq = EREAD1(iot, ioh, ESS_DSP_READ_STATUS);
+ if ((irq & (ESS_DSP_READ_ANYIRQ)) == 0) {
+ DPRINTF(("ess_intr_output: spurious interrupt %02x\n", irq));
+ return (0);
+ }
- sc->sc_out.nintr++;
+ if (sc->sc_out.intr == 0)
+ return (0);
- if (sc->sc_out.intr != 0)
- (*sc->sc_out.intr)(sc->sc_out.arg);
+ /* clear interrupt on Audio channel */
+ if (sc->sc_model == ESS_1788)
+ EREAD1(iot, ioh, ESS_CLEAR_INTR);
else
- return (0);
+ ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
+ ESS_AUDIO2_CTRL2_IRQ_LATCH);
+ sc->sc_out.nintr++;
+ (*sc->sc_out.intr)(sc->sc_out.arg);
return (1);
}
@@ -1360,19 +1673,24 @@ ess_intr_input(arg)
void *arg;
{
struct ess_softc *sc = arg;
- u_char x;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int irq;
DPRINTFN(1,("ess_intr_input: intr=%p\n", sc->sc_in.intr));
- /* clear interrupt on Audio channel 1*/
- x = EREAD1(sc->sc_iot, sc->sc_ioh, ESS_CLEAR_INTR);
+ irq = EREAD1(iot, ioh, ESS_DSP_READ_STATUS);
+ if ((irq & (ESS_DSP_READ_ANYIRQ)) == 0) {
+ DPRINTF(("ess_intr_input: spurious interrupt 0x%02x\n", irq));
+ return (0);
+ }
+ if (sc->sc_in.intr == 0)
+ return (0);
+ /* clear interrupt on Audio channel 1*/
+ EREAD1(sc->sc_iot, sc->sc_ioh, ESS_CLEAR_INTR);
sc->sc_in.nintr++;
-
- if (sc->sc_in.intr != 0)
- (*sc->sc_in.intr)(sc->sc_in.arg);
- else
- return (0);
+ (*sc->sc_in.intr)(sc->sc_in.arg);
return (1);
}
@@ -1402,6 +1720,14 @@ ess_set_port(addr, cp)
* single-channel gain value passed in, then we duplicate it
* to both left and right channels.
*/
+ case ESS_DAC_REC_VOL:
+ case ESS_MIC_REC_VOL:
+ case ESS_LINE_REC_VOL:
+ case ESS_SYNTH_REC_VOL:
+ case ESS_CD_REC_VOL:
+ case ESS_AUXB_REC_VOL:
+ if (sc->sc_model == ESS_1788)
+ return EINVAL;
case ESS_MASTER_VOL:
case ESS_DAC_PLAY_VOL:
case ESS_MIC_PLAY_VOL:
@@ -1409,12 +1735,6 @@ ess_set_port(addr, cp)
case ESS_SYNTH_PLAY_VOL:
case ESS_CD_PLAY_VOL:
case ESS_AUXB_PLAY_VOL:
- case ESS_DAC_REC_VOL:
- case ESS_MIC_REC_VOL:
- case ESS_LINE_REC_VOL:
- case ESS_SYNTH_REC_VOL:
- case ESS_CD_REC_VOL:
- case ESS_AUXB_REC_VOL:
case ESS_RECORD_VOL:
if (cp->type != AUDIO_MIXER_VALUE)
return EINVAL;
@@ -1470,7 +1790,9 @@ ess_set_port(addr, cp)
break;
case ESS_RECORD_SOURCE:
- if (cp->type == AUDIO_MIXER_SET)
+ if (cp->type == AUDIO_MIXER_ENUM)
+ return ess_set_in_port(sc, cp->un.ord);
+ else if (cp->type == AUDIO_MIXER_SET)
return ess_set_in_ports(sc, cp->un.mask);
else
return EINVAL;
@@ -1507,6 +1829,14 @@ ess_get_port(addr, cp)
DPRINTFN(5,("ess_get_port: port=%d\n", cp->dev));
switch (cp->dev) {
+ case ESS_DAC_REC_VOL:
+ case ESS_MIC_REC_VOL:
+ case ESS_LINE_REC_VOL:
+ case ESS_SYNTH_REC_VOL:
+ case ESS_CD_REC_VOL:
+ case ESS_AUXB_REC_VOL:
+ if (sc->sc_model == ESS_1788)
+ return EINVAL;
case ESS_DAC_PLAY_VOL:
case ESS_MIC_PLAY_VOL:
case ESS_LINE_PLAY_VOL:
@@ -1515,12 +1845,6 @@ ess_get_port(addr, cp)
case ESS_AUXB_PLAY_VOL:
case ESS_MASTER_VOL:
case ESS_PCSPEAKER_VOL:
- case ESS_DAC_REC_VOL:
- case ESS_MIC_REC_VOL:
- case ESS_LINE_REC_VOL:
- case ESS_SYNTH_REC_VOL:
- case ESS_CD_REC_VOL:
- case ESS_AUXB_REC_VOL:
case ESS_RECORD_VOL:
if (cp->dev == ESS_PCSPEAKER_VOL &&
cp->un.value.num_channels != 1)
@@ -1543,12 +1867,17 @@ ess_get_port(addr, cp)
break;
case ESS_MIC_PREAMP:
+ if (sc->sc_model == ESS_1788)
+ return EINVAL;
cp->un.ord = (ess_read_x_reg(sc, ESS_XCMD_PREAMP_CTRL) &
ESS_PREAMP_CTRL_ENABLE) ? 1 : 0;
break;
case ESS_RECORD_SOURCE:
- cp->un.mask = sc->in_mask;
+ if (sc->sc_model == ESS_1788)
+ cp->un.ord = sc->in_port;
+ else
+ cp->un.mask = sc->in_mask;
break;
case ESS_RECORD_MONITOR:
@@ -1568,9 +1897,7 @@ ess_query_devinfo(addr, dip)
void *addr;
mixer_devinfo_t *dip;
{
-#ifdef AUDIO_DEBUG
struct ess_softc *sc = addr;
-#endif
DPRINTFN(5,("ess_query_devinfo: model=%d index=%d\n",
sc->sc_model, dip->index));
@@ -1597,7 +1924,10 @@ ess_query_devinfo(addr, dip)
case ESS_MIC_PLAY_VOL:
dip->mixer_class = ESS_INPUT_CLASS;
dip->prev = AUDIO_MIXER_LAST;
- dip->next = ESS_MIC_PREAMP;
+ if (sc->sc_model == ESS_1788)
+ dip->next = AUDIO_MIXER_LAST;
+ else
+ dip->next = ESS_MIC_PREAMP;
strcpy(dip->label.name, AudioNmicrophone);
dip->type = AUDIO_MIXER_VALUE;
dip->un.v.num_channels = 2;
@@ -1672,9 +2002,10 @@ ess_query_devinfo(addr, dip)
dip->type = AUDIO_MIXER_CLASS;
return (0);
-
case ESS_DAC_REC_VOL:
- dip->mixer_class = ESS_RECORD_CLASS;
+ if (sc->sc_model == ESS_1788)
+ break;
+ dip->mixer_class = ESS_RECORD_CLASS;
dip->next = dip->prev = AUDIO_MIXER_LAST;
strcpy(dip->label.name, AudioNdac);
dip->type = AUDIO_MIXER_VALUE;
@@ -1683,6 +2014,8 @@ ess_query_devinfo(addr, dip)
return (0);
case ESS_MIC_REC_VOL:
+ if (sc->sc_model == ESS_1788)
+ break;
dip->mixer_class = ESS_RECORD_CLASS;
dip->next = dip->prev = AUDIO_MIXER_LAST;
strcpy(dip->label.name, AudioNmicrophone);
@@ -1692,6 +2025,8 @@ ess_query_devinfo(addr, dip)
return (0);
case ESS_LINE_REC_VOL:
+ if (sc->sc_model == ESS_1788)
+ break;
dip->mixer_class = ESS_RECORD_CLASS;
dip->next = dip->prev = AUDIO_MIXER_LAST;
strcpy(dip->label.name, AudioNline);
@@ -1701,6 +2036,8 @@ ess_query_devinfo(addr, dip)
return (0);
case ESS_SYNTH_REC_VOL:
+ if (sc->sc_model == ESS_1788)
+ break;
dip->mixer_class = ESS_RECORD_CLASS;
dip->next = dip->prev = AUDIO_MIXER_LAST;
strcpy(dip->label.name, AudioNfmsynth);
@@ -1710,6 +2047,8 @@ ess_query_devinfo(addr, dip)
return (0);
case ESS_CD_REC_VOL:
+ if (sc->sc_model == ESS_1788)
+ break;
dip->mixer_class = ESS_RECORD_CLASS;
dip->next = dip->prev = AUDIO_MIXER_LAST;
strcpy(dip->label.name, AudioNcd);
@@ -1719,6 +2058,8 @@ ess_query_devinfo(addr, dip)
return (0);
case ESS_AUXB_REC_VOL:
+ if (sc->sc_model == ESS_1788)
+ break;
dip->mixer_class = ESS_RECORD_CLASS;
dip->next = dip->prev = AUDIO_MIXER_LAST;
strcpy(dip->label.name, "auxb");
@@ -1728,6 +2069,8 @@ ess_query_devinfo(addr, dip)
return (0);
case ESS_MIC_PREAMP:
+ if (sc->sc_model == ESS_1788)
+ break;
dip->mixer_class = ESS_INPUT_CLASS;
dip->prev = ESS_MIC_PLAY_VOL;
dip->next = AUDIO_MIXER_LAST;
@@ -1752,21 +2095,40 @@ ess_query_devinfo(addr, dip)
case ESS_RECORD_SOURCE:
dip->next = dip->prev = AUDIO_MIXER_LAST;
strcpy(dip->label.name, AudioNsource);
- dip->type = AUDIO_MIXER_SET;
dip->mixer_class = ESS_RECORD_CLASS;
- dip->un.s.num_mem = 6;
- strcpy(dip->un.s.member[0].label.name, AudioNdac);
- dip->un.s.member[0].mask = 1 << ESS_DAC_REC_VOL;
- strcpy(dip->un.s.member[1].label.name, AudioNmicrophone);
- dip->un.s.member[1].mask = 1 << ESS_MIC_REC_VOL;
- strcpy(dip->un.s.member[2].label.name, AudioNline);
- dip->un.s.member[2].mask = 1 << ESS_LINE_REC_VOL;
- strcpy(dip->un.s.member[3].label.name, AudioNfmsynth);
- dip->un.s.member[3].mask = 1 << ESS_SYNTH_REC_VOL;
- strcpy(dip->un.s.member[4].label.name, AudioNcd);
- dip->un.s.member[4].mask = 1 << ESS_CD_REC_VOL;
- strcpy(dip->un.s.member[5].label.name, "auxb");
- dip->un.s.member[5].mask = 1 << ESS_AUXB_REC_VOL;
+ if (sc->sc_model == ESS_1788) {
+ /* The 1788 doesn't use the input mixer control that the 1888 uses,
+ * because it's a pain when you only have one mixer.
+ * Perhaps it could be emulated by keeping both sets of gain
+ * values, and doing a `context switch' of the mixer registers
+ * when shifting from playing to recording. Yuk.
+ */
+ dip->type = AUDIO_MIXER_ENUM;
+ dip->un.e.num_mem = 4;
+ strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
+ dip->un.e.member[0].ord = ESS_SOURCE_MIC;
+ strcpy(dip->un.e.member[1].label.name, AudioNline);
+ dip->un.e.member[1].ord = ESS_SOURCE_LINE;
+ strcpy(dip->un.e.member[2].label.name, AudioNcd);
+ dip->un.e.member[2].ord = ESS_SOURCE_CD;
+ strcpy(dip->un.e.member[3].label.name, AudioNmixerout);
+ dip->un.e.member[3].ord = ESS_SOURCE_MIXER;
+ } else {
+ dip->type = AUDIO_MIXER_SET;
+ dip->un.s.num_mem = 6;
+ strcpy(dip->un.s.member[0].label.name, AudioNdac);
+ dip->un.s.member[0].mask = 1 << ESS_DAC_REC_VOL;
+ strcpy(dip->un.s.member[1].label.name, AudioNmicrophone);
+ dip->un.s.member[1].mask = 1 << ESS_MIC_REC_VOL;
+ strcpy(dip->un.s.member[2].label.name, AudioNline);
+ dip->un.s.member[2].mask = 1 << ESS_LINE_REC_VOL;
+ strcpy(dip->un.s.member[3].label.name, AudioNfmsynth);
+ dip->un.s.member[3].mask = 1 << ESS_SYNTH_REC_VOL;
+ strcpy(dip->un.s.member[4].label.name, AudioNcd);
+ dip->un.s.member[4].mask = 1 << ESS_CD_REC_VOL;
+ strcpy(dip->un.s.member[5].label.name, "auxb");
+ dip->un.s.member[5].mask = 1 << ESS_AUXB_REC_VOL;
+ }
return (0);
case ESS_RECORD_CLASS:
@@ -1909,28 +2271,31 @@ ess_set_gain(sc, port, on)
switch (port) {
case ESS_MASTER_VOL:
- src = 0x32;
+ src = ESS_MREG_VOLUME_MASTER;
break;
case ESS_DAC_PLAY_VOL:
- src = 0x7C;
+ if (sc->sc_model == ESS_1788)
+ src = ESS_MREG_VOLUME_VOICE;
+ else
+ src = 0x7C;
break;
case ESS_MIC_PLAY_VOL:
- src = 0x1A;
+ src = ESS_MREG_VOLUME_MIC;
break;
case ESS_LINE_PLAY_VOL:
- src = 0x3E;
+ src = ESS_MREG_VOLUME_LINE;
break;
case ESS_SYNTH_PLAY_VOL:
- src = 0x36;
+ src = ESS_MREG_VOLUME_SYNTH;
break;
case ESS_CD_PLAY_VOL:
- src = 0x38;
+ src = ESS_MREG_VOLUME_CD;
break;
case ESS_AUXB_PLAY_VOL:
- src = 0x3A;
+ src = ESS_MREG_VOLUME_AUXB;
break;
case ESS_PCSPEAKER_VOL:
- src = 0x3C;
+ src = ESS_MREG_VOLUME_PCSPKR;
stereo = 0;
break;
case ESS_DAC_REC_VOL:
@@ -1952,13 +2317,17 @@ ess_set_gain(sc, port, on)
src = 0x6C;
break;
case ESS_RECORD_VOL:
- src = 0xB4;
+ src = ESS_XCMD_VOLIN_CTRL;
mix = 0;
break;
default:
return;
}
+ /* 1788 doesn't have a separate recording mixer */
+ if (sc->sc_model == ESS_1788 && mix == 1 && src > 0x62)
+ return;
+
if (on) {
left = sc->gain[port][ESS_LEFT];
right = sc->gain[port][ESS_RIGHT];
@@ -1977,6 +2346,44 @@ ess_set_gain(sc, port, on)
ess_write_x_reg(sc, src, gain);
}
+/* Set the input device on devices without an input mixer. */
+int
+ess_set_in_port(sc, ord)
+ struct ess_softc *sc;
+ int ord;
+{
+ mixer_devinfo_t di;
+ int i, val;
+
+ DPRINTF(("ess_set_in_port: ord=0x%x\n", ord));
+
+ /*
+ * Get the device info for the record source control,
+ * including the list of available sources.
+ */
+ di.index = ESS_RECORD_SOURCE;
+ if (ess_query_devinfo(sc, &di))
+ return EINVAL;
+
+ val = -1;
+ for (i = 0; i < di.un.e.num_mem; i++) {
+ if (ord == di.un.e.member[i].ord) {
+ val = ord;
+ break;
+ }
+ }
+
+ /* See if the given ord value was anywhere in the list. */
+ if (val == -1)
+ return EINVAL;
+
+ ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, val);
+ sc->in_port = val;
+
+ return (0);
+}
+
+/* Set the input device levels on input-mixer-enabled devices. */
int
ess_set_in_ports(sc, mask)
struct ess_softc *sc;
@@ -2001,8 +2408,7 @@ ess_set_in_ports(sc, mask)
* Set or disable the record volume control for each of the
* possible sources.
*/
- for (i = 0; i < di.un.s.num_mem; i++)
- {
+ for (i = 0; i < di.un.s.num_mem; i++) {
/*
* Calculate the source port number from its mask.
*/
@@ -2040,8 +2446,8 @@ ess_speaker_on(sc)
struct ess_softc *sc;
{
/* Disable mute on left- and right-master volume. */
- ess_clear_mreg_bits(sc, 0x60, 0x40);
- ess_clear_mreg_bits(sc, 0x62, 0x40);
+ ess_clear_mreg_bits(sc, ESS_MREG_VOLUME_LEFT, ESS_VOLUME_MUTE);
+ ess_clear_mreg_bits(sc, ESS_MREG_VOLUME_RIGHT, ESS_VOLUME_MUTE);
}
void
@@ -2049,8 +2455,8 @@ ess_speaker_off(sc)
struct ess_softc *sc;
{
/* Enable mute on left- and right-master volume. */
- ess_set_mreg_bits(sc, 0x60, 0x40);
- ess_set_mreg_bits(sc, 0x62, 0x40);
+ ess_set_mreg_bits(sc, ESS_MREG_VOLUME_LEFT, ESS_VOLUME_MUTE);
+ ess_set_mreg_bits(sc, ESS_MREG_VOLUME_RIGHT, ESS_VOLUME_MUTE);
}
/*
@@ -2095,10 +2501,7 @@ u_char
ess_get_dsp_status(sc)
struct ess_softc *sc;
{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
-
- return (EREAD1(iot, ioh, ESS_DSP_RW_STATUS));
+ return (EREAD1(sc->sc_iot, sc->sc_ioh, ESS_DSP_READ_STATUS));
}
@@ -2110,7 +2513,7 @@ u_char
ess_dsp_read_ready(sc)
struct ess_softc *sc;
{
- return (((ess_get_dsp_status(sc) & ESS_DSP_READ_MASK) ==
+ return (((ess_get_dsp_status(sc) & ESS_DSP_READ_READY) ==
ESS_DSP_READ_READY) ? 1 : 0);
}
@@ -2213,7 +2616,7 @@ ess_read_x_reg(sc, reg)
DPRINTF(("Error reading extended register 0x%02x\n", reg));
/* REVISIT: what if an error is returned above? */
val = ess_rdsp(sc);
- DPRINTFN(2,("ess_write_x_reg: %02x=%02x\n", reg, val));
+ DPRINTFN(2,("ess_read_x_reg: %02x=%02x\n", reg, val));
return val;
}
diff --git a/sys/dev/isa/essreg.h b/sys/dev/isa/essreg.h
index 551689c325a..3125e99c8c2 100644
--- a/sys/dev/isa/essreg.h
+++ b/sys/dev/isa/essreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: essreg.h,v 1.7 1999/02/15 04:54:35 hubertf Exp $ */
+/* $NetBSD: essreg.h,v 1.8 1999/03/02 20:36:51 nathanw Exp $ */
/*
* Copyright 1997
* Digital Equipment Corporation. All rights reserved.
@@ -33,7 +33,7 @@
*/
/*
-** @(#) $RCSfile: essreg.h,v $ $Revision: 1.7 $ (SHARK) $Date: 1999/02/15 04:54:35 $
+** @(#) $RCSfile: essreg.h,v $ $Revision: 1.8 $ (SHARK) $Date: 1999/03/02 20:36:51 $
**
**++
**
@@ -125,8 +125,12 @@
#define ESS_DRQ_CTRL_PU 0x10
#define ESS_DRQ_CTRL_EXT 0x40
#define ESS_XCMD_VOLIN_CTRL 0xB4 /* stereo input volume control */
+#define ESS_1788_XCMD_AUDIO_CTRL0 0xB6
+#define ESS_CTRL0_SIGNED 0x00
+#define ESS_CTRL0_UNSIGNED 0x80
#define ESS_XCMD_AUDIO1_CTRL1 0xB7 /* */
#define ESS_AUDIO1_CTRL1_FIFO_CONNECT 0x80 /* 1=connected */
+#define ESS_AUDIO1_CTRL1_FIFO_MONO 0x40 /* 0=stereo/1=mono */
#define ESS_AUDIO1_CTRL1_FIFO_SIGNED 0x20 /* 0=unsigned/1=signed */
#define ESS_AUDIO1_CTRL1_FIFO_STEREO 0x08 /* 0=mono/1=stereo */
#define ESS_AUDIO1_CTRL1_FIFO_SIZE 0x04 /* 0=8-bit/1=16-bit */
@@ -225,12 +229,19 @@
#define ESS_DSP_READ 0x0A
#define ESS_DSP_WRITE 0x0C
-#define ESS_DSP_RW_STATUS 0x0C
#define ESS_CLEAR_INTR 0x0E
-#define ESS_DSP_READ_STATUS 0x0C
-#define ESS_DSP_READ_MASK 0x40
-#define ESS_DSP_READ_READY 0x40
+#define ESS_DSP_READ_STATUS 0x0C
+#define ESS_DSP_READ_READY 0x40
+#define ESS_DSP_READ_FULL 0x20 /* FIFO full */
+#define ESS_DSP_READ_EMPTY 0x10 /* FIFO empty */
+#define ESS_DSP_READ_HALF 0x08 /* FIFO half-empty */
+#define ESS_DSP_READ_IRQ 0x04 /* IRQ generated */
+#define ESS_DSP_READ_HALF_IRQ 0x02 /* " from half-empty flag change */
+#define ESS_DSP_READ_OFLOW 0x01 /* " from DMA counter overflow */
+#define ESS_DSP_READ_ANYIRQ (ESS_DSP_READ_IRQ | \
+ ESS_DSP_READ_HALF_IRQ | \
+ ESS_DSP_READ_OFLOW)
#define ESS_DSP_WRITE_STATUS 0x0C
#define ESS_DSP_WRITE_MASK 0x80
@@ -245,6 +256,23 @@
/*
* ESS Mixer registers
*/
+#define ESS_MREG_VOLUME_VOICE 0x14
+#define ESS_MREG_VOLUME_MIC 0x1A
+#define ESS_MREG_ADC_SOURCE 0x1C
+#define ESS_SOURCE_MIC 0x00
+#define ESS_SOURCE_CD 0x02
+#define ESS_SOURCE_LINE 0x06
+#define ESS_SOURCE_MIXER 0x07
+#define ESS_MREG_VOLUME_MASTER 0x32
+#define ESS_MREG_VOLUME_SYNTH 0x36
+#define ESS_MREG_VOLUME_CD 0x38
+#define ESS_MREG_VOLUME_AUXB 0x3A
+#define ESS_MREG_VOLUME_PCSPKR 0x3C
+#define ESS_MREG_VOLUME_LINE 0x3E
+#define ESS_MREG_VOLUME_LEFT 0x60
+#define ESS_MREG_VOLUME_RIGHT 0x62
+#define ESS_VOLUME_MUTE 0x40
+#define ESS_MREG_VOLUME_CTRL 0x64
#define ESS_MREG_SAMPLE_RATE 0x70 /* sample rate for Audio2 channel */
#define ESS_MREG_FILTER_CLOCK 0x72 /* filter clock for Audio2 channel */
#define ESS_MREG_XFER_COUNTLO 0x74 /* low-byte of DMA transfer size */
diff --git a/sys/dev/isa/essvar.h b/sys/dev/isa/essvar.h
index 1835fb09ef5..abb3e043563 100644
--- a/sys/dev/isa/essvar.h
+++ b/sys/dev/isa/essvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: essvar.h,v 1.11 1999/02/19 16:15:06 mycroft Exp $ */
+/* $NetBSD: essvar.h,v 1.12 1999/03/02 20:36:51 nathanw Exp $ */
/*
* Copyright 1997
* Digital Equipment Corporation. All rights reserved.
@@ -33,7 +33,7 @@
*/
/*
-** @(#) $RCSfile: essvar.h,v $ $Revision: 1.11 $ (SHARK) $Date: 1999/02/19 16:15:06 $
+** @(#) $RCSfile: essvar.h,v $ $Revision: 1.12 $ (SHARK) $Date: 1999/03/02 20:36:51 $
**
**++
**
@@ -74,21 +74,25 @@
#define ESS_PCSPEAKER_VOL 8
#define ESS_OUTPUT_CLASS 9
-#define ESS_DAC_REC_VOL 10
-#define ESS_MIC_REC_VOL 11
-#define ESS_LINE_REC_VOL 12
-#define ESS_SYNTH_REC_VOL 13
-#define ESS_CD_REC_VOL 14
-#define ESS_AUXB_REC_VOL 15
-#define ESS_MIC_PREAMP 16
-#define ESS_RECORD_VOL 17
-#define ESS_RECORD_SOURCE 18
-#define ESS_RECORD_CLASS 19
+#define ESS_RECORD_MONITOR 10
+#define ESS_MONITOR_CLASS 11
-#define ESS_RECORD_MONITOR 20
-#define ESS_MONITOR_CLASS 21
+#define ESS_RECORD_VOL 12
+#define ESS_RECORD_SOURCE 13
+#define ESS_RECORD_CLASS 14
-#define ESS_NDEVS 22
+#define ESS_1788_NDEVS 15
+
+#define ESS_DAC_REC_VOL 15
+#define ESS_MIC_REC_VOL 16
+#define ESS_LINE_REC_VOL 17
+#define ESS_SYNTH_REC_VOL 18
+#define ESS_CD_REC_VOL 19
+#define ESS_AUXB_REC_VOL 20
+#define ESS_MIC_PREAMP 21
+
+#define ESS_1888_NDEVS 22
+#define ESS_MAX_NDEVS 22
struct ess_audio_channel
{
@@ -116,7 +120,8 @@ struct ess_softc
u_short sc_open; /* reference count of open calls */
- u_char gain[ESS_NDEVS][2]; /* kept in input levels */
+ int ndevs;
+ u_char gain[ESS_MAX_NDEVS][2]; /* kept in input levels */
#define ESS_LEFT 0
#define ESS_RIGHT 1
@@ -134,6 +139,7 @@ struct ess_softc
#define ESS_1888 1
#define ESS_1887 2
#define ESS_888 3
+#define ESS_1788 4
u_int sc_version; /* Legacy ES688/ES1688 ID */
};