summaryrefslogtreecommitdiff
path: root/sys/dev/pci/eap.c
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1999-10-05 19:24:43 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1999-10-05 19:24:43 +0000
commit8d16419aa58dd2ae0803358e6a1548b6598fbf95 (patch)
treee1801aa77c6fe3360fb093d00ec99b460477690e /sys/dev/pci/eap.c
parentaea39f84cbddd702393f5bc20924739da273dc76 (diff)
Ensoniq ES1371 support.
Thanks to Ezra Story (ezy@panix.com)
Diffstat (limited to 'sys/dev/pci/eap.c')
-rw-r--r--sys/dev/pci/eap.c748
1 files changed, 592 insertions, 156 deletions
diff --git a/sys/dev/pci/eap.c b/sys/dev/pci/eap.c
index c4326b6f0d5..678171616f4 100644
--- a/sys/dev/pci/eap.c
+++ b/sys/dev/pci/eap.c
@@ -1,16 +1,12 @@
-/* $OpenBSD: eap.c,v 1.5 1999/03/23 08:00:34 deraadt Exp $ */
-/* $NetBSD: eap.c,v 1.17 1998/08/25 04:56:01 thorpej Exp $ */
+/* $OpenBSD: eap.c,v 1.6 1999/10/05 19:24:42 csapuntz Exp $ */
+/* $NetBSD: eap.c,v 1.25 1999/02/18 07:59:30 mycroft Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
- * Author: Lennart Augustsson <augustss@cs.chalmers.se>
- * Charles M. Hannum <mycroft@netbsd.org>
- *
- * Debugging: Andreas Gustafsson <gson@araneus.fi>
- * Testing: Chuck Cranor <chuck@maria.wustl.edu>
- * Phil Nelson <phil@cs.wwu.edu>
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson <augustss@netbsd.org> and Charles M. Hannum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,13 +37,25 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * Debugging: Andreas Gustafsson <gson@araneus.fi>
+ * Testing: Chuck Cranor <chuck@maria.wustl.edu>
+ * Phil Nelson <phil@cs.wwu.edu>
+ */
+
/*
* Ensoniq AudoiPCI ES1370 + AK4531 driver.
* Data sheets can be found at
* http://www.ensoniq.com/multimedia/semi_html/html/es1370.zip
* and
* http://206.214.38.151/pdf/4531.pdf
+ *
+ * Added Creative Ensoniq support: ES1371 + AC97 = hack city.
+ * -- Ezra Story <ezy@panix.com>
+ * Check es1371.zip from above, and the Audio Codec 97 spec from
+ * intel.com.
*/
+
#include <sys/param.h>
#include <sys/systm.h>
@@ -62,17 +70,14 @@
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
+#include <dev/ic/ac97.h>
#include <machine/bus.h>
-#ifndef BUS_DMA_COHERENT
-#define BUS_DMA_COHERENT 0 /* XXX */
-#endif
-
struct cfdriver eap_cd = {
NULL, "eap", DV_DULL
};
-
+
#define PCI_CBIO 0x10
#define EAP_ICSC 0x00 /* interrupt / chip select control */
@@ -100,6 +105,7 @@ struct cfdriver eap_cd = {
#define EAP_PCLKBITS 0x1fff0000
#define EAP_XTCL1 0x40000000
#define EAP_ADC_STOP 0x80000000
+#define E1371_SYNC_RES (1<<14)
#define EAP_ICSS 0x04 /* interrupt / chip select status */
#define EAP_I_ADC 0x00000001
@@ -120,6 +126,49 @@ struct cfdriver eap_cd = {
#define EAP_CODEC 0x10
#define EAP_SET_CODEC(a,d) (((a)<<8) | (d))
+/* ES1371 Registers */
+#define E1371_CODEC 0x14
+#define E1371_CODEC_WIP (1<<30)
+#define E1371_CODEC_VALID (1<<31)
+#define E1371_CODEC_READ (1<<23)
+#define E1371_SET_CODEC(a,d) (((a)<<16) | (d))
+#define E1371_SRC 0x10
+#define E1371_SRC_RAMWE (1<<24)
+#define E1371_SRC_RBUSY (1<<23)
+#define E1371_SRC_DISABLE (1<<22)
+#define E1371_SRC_DISP1 (1<<21)
+#define E1371_SRC_DISP2 (1<<20)
+#define E1371_SRC_DISREC (1<<19)
+#define E1371_SRC_ADDR(a) ((a)<<25)
+#define E1371_SRC_DATA(d) (d)
+#define E1371_SRC_DATAMASK 0xffff
+#define E1371_LEGACY 0x18
+
+/* ES1371 Sample rate converter registers */
+#define ESRC_ADC 0x78
+#define ESRC_DAC1 0x74
+#define ESRC_DAC2 0x70
+#define ESRC_ADC_VOLL 0x6c
+#define ESRC_ADC_VOLR 0x6d
+#define ESRC_DAC1_VOLL 0x7c
+#define ESRC_DAC1_VOLR 0x7d
+#define ESRC_DAC2_VOLL 0x7e
+#define ESRC_DAC2_VOLR 0x7f
+#define ESRC_TRUNC_N 0x00
+#define ESRC_IREGS 0x01
+#define ESRC_ACF 0x02
+#define ESRC_VFF 0x03
+#define ESRC_SET_TRUNC(n) ((n)<<9)
+#define ESRC_SET_N(n) ((n)<<4)
+#define ESRC_SMF 0x8000
+#define ESRC_SET_VFI(n) ((n)<<10)
+#define ESRC_SET_ACI(n) (n)
+#define ESRC_SET_ADC_VOL(n) ((n)<<8)
+#define ESRC_SET_DAC_VOLI(n) ((n)<<12)
+#define ESRC_SET_DAC_VOLF(n) (n)
+#define SRC_MAGIC ((1<15)|(1<<13)|(1<<11)|(1<<9))
+
+
#define EAP_SIC 0x20
#define EAP_P1_S_MB 0x00000001
#define EAP_P1_S_EB 0x00000002
@@ -159,6 +208,10 @@ struct cfdriver eap_cd = {
#define EAP_ADC_SIZE 0x34
#define EAP_SET_SIZE(c,s) (((c)<<16) | (s))
+#define EAP_READ_TIMEOUT 5000000
+#define EAP_WRITE_TIMEOUT 5000000
+
+
#define EAP_XTAL_FREQ 1411200 /* 22.5792 / 16 MHz */
/* AK4531 registers */
@@ -211,37 +264,38 @@ struct cfdriver eap_cd = {
#define AK_CS 0x17
#define AK_ADSEL 0x18
#define AK_MGAIN 0x19
+#define AK_NPORTS 0x20
-#define AK_NPORTS 16
+#define MAX_NPORTS AK_NPORTS
+/* Not sensical for AC97? */
#define VOL_TO_ATT5(v) (0x1f - ((v) >> 3))
#define VOL_TO_GAIN5(v) VOL_TO_ATT5(v)
#define ATT5_TO_VOL(v) ((0x1f - (v)) << 3)
#define GAIN5_TO_VOL(v) ATT5_TO_VOL(v)
#define VOL_0DB 200
+/* Futzable parms */
#define EAP_MASTER_VOL 0
#define EAP_VOICE_VOL 1
-#define EAP_FM_VOL 2
+#define EAP_FM_VOL 2
+#define EAP_VIDEO_VOL 2 /* ES1371 */
#define EAP_CD_VOL 3
#define EAP_LINE_VOL 4
#define EAP_AUX_VOL 5
#define EAP_MIC_VOL 6
#define EAP_RECORD_SOURCE 7
#define EAP_OUTPUT_SELECT 8
-#define EAP_MIC_PREAMP 9
+#define EAP_MIC_PREAMP 9
#define EAP_OUTPUT_CLASS 10
#define EAP_RECORD_CLASS 11
#define EAP_INPUT_CLASS 12
+/* Debug */
#ifdef AUDIO_DEBUG
#define DPRINTF(x) if (eapdebug) printf x
#define DPRINTFN(n,x) if (eapdebug>(n)) printf x
-#ifdef EAP_DEBUG
-int eapdebug = EAP_DEBUG;
-#else
-int eapdebug = 0;
-#endif
+int eapdebug = 20;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -259,8 +313,8 @@ struct eap_dma {
size_t size;
struct eap_dma *next;
};
-#define DMAADDR(map) ((map)->segs[0].ds_addr)
-#define KERNADDR(map) ((void *)((map)->addr))
+#define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
+#define KERNADDR(p) ((void *)((p)->addr))
struct eap_softc {
struct device sc_dev; /* base device */
@@ -283,10 +337,14 @@ struct eap_softc {
char sc_rrun;
#endif
- u_char sc_port[AK_NPORTS]; /* mirror of the hardware setting */
+ u_short sc_port[MAX_NPORTS]; /* mirror of the hardware setting */
u_int sc_record_source; /* recording source mask */
u_int sc_output_source; /* output source mask */
u_int sc_mic_preamp;
+ char sc_1371; /* Using ES1371/AC97 codec */
+
+ struct ac97_codec_if *codec_if;
+ struct ac97_host_if host_if;
};
int eap_allocmem __P((struct eap_softc *, size_t, size_t, struct eap_dma *));
@@ -312,17 +370,32 @@ int eap_trigger_input __P((void *, void *, void *, int, void (*)(void *),
void *, struct audio_params *));
int eap_halt_output __P((void *));
int eap_halt_input __P((void *));
+void eap_write_codec __P((struct eap_softc *, int, int));
int eap_getdev __P((void *, struct audio_device *));
int eap_mixer_set_port __P((void *, mixer_ctrl_t *));
int eap_mixer_get_port __P((void *, mixer_ctrl_t *));
+int eap1371_mixer_set_port __P((void *, mixer_ctrl_t *));
+int eap1371_mixer_get_port __P((void *, mixer_ctrl_t *));
int eap_query_devinfo __P((void *, mixer_devinfo_t *));
void *eap_malloc __P((void *, u_long, int, int));
void eap_free __P((void *, void *, int));
-u_long eap_round __P((void *, u_long));
+u_long eap_round_buffersize __P((void *, u_long));
int eap_mappage __P((void *, void *, int, int));
int eap_get_props __P((void *));
-void eap_write_codec __P((struct eap_softc *sc, int a, int d));
void eap_set_mixer __P((struct eap_softc *sc, int a, int d));
+void eap1371_src_wait __P((struct eap_softc *sc));
+void eap1371_set_adc_rate __P((struct eap_softc *sc, int rate));
+void eap1371_set_dac_rate __P((struct eap_softc *sc, int rate, int which));
+int eap1371_src_read __P((struct eap_softc *sc, int a));
+void eap1371_src_write __P((struct eap_softc *sc, int a, int d));
+int eap1371_query_devinfo __P((void *addr, mixer_devinfo_t *dip));
+
+int eap1371_attach_codec __P((void *sc, struct ac97_codec_if *));
+int eap1371_read_codec __P((void *sc, u_int8_t a, u_int16_t *d));
+int eap1371_write_codec __P((void *sc, u_int8_t a, u_int16_t d));
+void eap1371_reset_codec __P((void *sc));
+int eap1371_get_portnum_by_name __P((struct eap_softc *, char *, char *,
+ char *));
struct audio_hw_if eap_hw_if = {
eap_open,
@@ -346,7 +419,7 @@ struct audio_hw_if eap_hw_if = {
eap_query_devinfo,
eap_malloc,
eap_free,
- eap_round,
+ eap_round_buffersize,
eap_mappage,
eap_get_props,
eap_trigger_output,
@@ -362,16 +435,21 @@ struct audio_device eap_device = {
int
eap_match(parent, match, aux)
struct device *parent;
- void *match, *aux;
+ void *match;
+ void *aux;
{
struct pci_attach_args *pa = (struct pci_attach_args *) aux;
if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_ENSONIQ)
return (0);
- if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_ENSONIQ_AUDIOPCI)
- return (0);
+ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENSONIQ_AUDIOPCI) {
+ return (1);
+ }
+ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENSONIQ_AUDIOPCI97) {
+ return (1);
+ }
- return (1);
+ return (0);
}
void
@@ -379,19 +457,204 @@ eap_write_codec(sc, a, d)
struct eap_softc *sc;
int a, d;
{
- int icss;
- int timeo = 4096;
+
+ int icss, to = EAP_WRITE_TIMEOUT;
do {
- icss = EREAD4(sc, EAP_ICSS);
+ icss = EREAD4(sc, EAP_ICSS);
DPRINTFN(5,("eap: codec %d prog: icss=0x%08x\n", a, icss));
- timeo--;
- } while((timeo > 0) && (icss & EAP_CWRIP));
+ if (!to--) {
+ printf("eap: timeout writing to codec\n");
+ return;
+ }
+ } while(to && icss & EAP_CWRIP); /* XXX could use CSTAT here */
+ EWRITE4(sc, EAP_CODEC, EAP_SET_CODEC(a, d));
+}
+
+
+int
+eap1371_read_codec(sc_, a, d)
+ void *sc_;
+ u_int8_t a;
+ u_int16_t *d;
+{
+ struct eap_softc *sc = sc_;
+ int to;
+ int cdc;
+
+ to = EAP_WRITE_TIMEOUT;
+ do {
+ cdc = EREAD4(sc, E1371_CODEC);
+ if (!to--) {
+ printf("eap: timeout writing to codec\n");
+ return 1;
+ }
+ } while (cdc & E1371_CODEC_WIP);
+
+ /* just do it */
+ eap1371_src_wait(sc);
+ EWRITE4(sc, E1371_CODEC, E1371_SET_CODEC(a, 0) | E1371_CODEC_READ);
+
+ for (to = 0; to < EAP_WRITE_TIMEOUT; to++) {
+ if ((cdc = EREAD4(sc, E1371_CODEC)) & E1371_CODEC_VALID)
+ break;
+ }
- if (timeo == 0)
- DPRINTF(("eap: codec write timeout, %d prog: icss=0x%08x\n",
- a, icss));
- EWRITE4(sc, EAP_CODEC, EAP_SET_CODEC(a, d));
+ if (to == EAP_WRITE_TIMEOUT) {
+ DPRINTF(("eap1371: read codec timeout\n"));
+ }
+
+ *d = cdc & 0xffff;
+
+ DPRINTFN(10, ("eap1371: reading codec (%x) = %x\n", a, *d));
+
+ return (0);
+}
+
+int
+eap1371_write_codec(sc_, a, d)
+ void *sc_;
+ u_int8_t a;
+ u_int16_t d;
+{
+ struct eap_softc *sc = sc_;
+ int to;
+ int cdc;
+
+ to = EAP_WRITE_TIMEOUT;
+ do {
+ cdc = EREAD4(sc, E1371_CODEC);
+ if (!to--) {
+ printf("eap: timeout writing to codec\n");
+ return 1;
+ }
+ } while (cdc & E1371_CODEC_WIP);
+
+ /* just do it */
+ eap1371_src_wait(sc);
+ EWRITE4(sc, E1371_CODEC, E1371_SET_CODEC(a, d));
+ DPRINTFN(10, ("eap1371: writing codec %x --> %x\n", d, a));
+
+ return (0);
+}
+
+void
+eap1371_src_wait(sc)
+ struct eap_softc *sc;
+{
+ int to;
+ int src;
+
+ to = EAP_READ_TIMEOUT;
+ do {
+ src = EREAD4(sc, E1371_SRC);
+ if (!to--) {
+ printf("eap: timeout waiting for sample rate"
+ "converter\n");
+ return;
+ }
+ } while (src & E1371_SRC_RBUSY);
+}
+
+int
+eap1371_src_read(sc, a)
+ struct eap_softc *sc;
+ int a;
+{
+ int r;
+
+ eap1371_src_wait(sc);
+ r = EREAD4(sc, E1371_SRC) & (E1371_SRC_DISABLE | E1371_SRC_DISP1 |
+ E1371_SRC_DISP2 | E1371_SRC_DISREC);
+ r |= E1371_SRC_ADDR(a);
+ EWRITE4(sc, E1371_SRC, r);
+ r = EREAD4(sc, E1371_SRC) & E1371_SRC_DATAMASK;
+ return r;
+}
+
+void
+eap1371_src_write(sc, a, d)
+ struct eap_softc *sc;
+ int a,d;
+{
+ int r;
+
+ eap1371_src_wait(sc);
+ r = EREAD4(sc, E1371_SRC) & (E1371_SRC_DISABLE | E1371_SRC_DISP1 |
+ E1371_SRC_DISP2 | E1371_SRC_DISREC);
+ r |= E1371_SRC_RAMWE | E1371_SRC_ADDR(a) | E1371_SRC_DATA(d);
+ EWRITE4(sc, E1371_SRC, r);
+}
+
+void
+eap1371_set_adc_rate(sc, rate)
+ struct eap_softc *sc;
+ int rate;
+{
+ int freq, n, truncm;
+ int out;
+
+ /* Whatever, it works, so I'll leave it :) */
+
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 4000)
+ rate = 4000;
+ n = rate / 3000;
+ if ((1 << n) & SRC_MAGIC)
+ n--;
+ truncm = ((21 * n) - 1) | 1;
+ freq = ((48000 << 15) / rate) * n;
+ if (rate >= 24000) {
+ if (truncm > 239)
+ truncm = 239;
+ out = ESRC_SET_TRUNC((239 - truncm) / 2);
+ } else {
+ if (truncm > 119)
+ truncm = 119;
+ out = ESRC_SMF | ESRC_SET_TRUNC((119 - truncm) / 2);
+ }
+ out |= ESRC_SET_N(n);
+ eap1371_src_write(sc, ESRC_ADC+ESRC_TRUNC_N, out);
+
+
+ out = eap1371_src_read(sc, ESRC_ADC+ESRC_IREGS) & 0xff;
+ eap1371_src_write(sc, ESRC_ADC+ESRC_IREGS, out |
+ ESRC_SET_VFI(freq >> 15));
+ eap1371_src_write(sc, ESRC_ADC+ESRC_VFF, freq & 0x7fff);
+ eap1371_src_write(sc, ESRC_ADC_VOLL, ESRC_SET_ADC_VOL(n));
+ eap1371_src_write(sc, ESRC_ADC_VOLR, ESRC_SET_ADC_VOL(n));
+}
+
+void
+eap1371_set_dac_rate(sc, rate, which)
+ struct eap_softc *sc;
+ int rate;
+ int which;
+{
+ int dac = (which == 1) ? ESRC_DAC1 : ESRC_DAC2;
+ int freq, r;
+
+ /* Whatever, it works, so I'll leave it :) */
+
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 4000)
+ rate = 4000;
+ freq = (rate << 15) / 3000;
+
+ eap1371_src_wait(sc);
+ r = EREAD4(sc, E1371_SRC) & (E1371_SRC_DISABLE |
+ E1371_SRC_DISP2 | E1371_SRC_DISP1 | E1371_SRC_DISREC);
+ r |= (which == 1) ? E1371_SRC_DISP1 : E1371_SRC_DISP2;
+ EWRITE4(sc, E1371_SRC, r);
+ r = eap1371_src_read(sc, dac + ESRC_IREGS) & 0x00ff;
+ eap1371_src_write(sc, dac + ESRC_IREGS, r | ((freq >> 5) & 0xfc00));
+ eap1371_src_write(sc, dac + ESRC_VFF, freq & 0x7fff);
+ r = EREAD4(sc, E1371_SRC) & (E1371_SRC_DISABLE |
+ E1371_SRC_DISP2 | E1371_SRC_DISP1 | E1371_SRC_DISREC);
+ r &= ~((which == 1) ? E1371_SRC_DISP1 : E1371_SRC_DISP2);
+ EWRITE4(sc, E1371_SRC, r);
}
void
@@ -404,18 +667,16 @@ eap_attach(parent, self, aux)
struct pci_attach_args *pa = (struct pci_attach_args *)aux;
pci_chipset_tag_t pc = pa->pa_pc;
char const *intrstr;
- bus_addr_t iobase;
- bus_size_t iosize;
pci_intr_handle_t ih;
pcireg_t csr;
mixer_ctrl_t ctl;
+ int i;
+ /* Flag if we're "creative" */
+ sc->sc_1371 = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENSONIQ_AUDIOPCI97);
/* Map I/O register */
- if (pci_io_find(pc, pa->pa_tag, PCI_CBIO, &iobase, &iosize)) {
- printf("\n%s: can't find i/o base\n", sc->sc_dev.dv_xname);
- return;
- }
- if (bus_space_map(sc->iot, iobase, iosize, 0, &sc->ioh)) {
+ if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
+ &sc->iot, &sc->ioh, NULL, NULL)) {
printf("\n%s: can't map i/o space\n", sc->sc_dev.dv_xname);
return;
}
@@ -429,56 +690,168 @@ eap_attach(parent, self, aux)
/* Map and establish the interrupt. */
if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
- pa->pa_intrline, &ih)) {
+ pa->pa_intrline, &ih)) {
printf("\n%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
return;
}
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, eap_intr, sc,
- sc->sc_dev.dv_xname);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, eap_intr, sc,
+ sc->sc_dev.dv_xname);
if (sc->sc_ih == NULL) {
printf("\n%s: couldn't establish interrupt",
- sc->sc_dev.dv_xname);
+ sc->sc_dev.dv_xname);
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
return;
}
- printf(": %s\n", intrstr);
-
- /* Enable interrupts and looping mode. */
- EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
- EWRITE4(sc, EAP_ICSC, EAP_CDC_EN); /* enable the parts we need */
-
- eap_write_codec(sc, AK_RESET, AK_PD); /* reset codec */
- eap_write_codec(sc, AK_RESET, AK_PD | AK_NRST); /* normal operation */
- eap_write_codec(sc, AK_CS, 0x0); /* select codec clocks */
-
- /* Enable all relevant mixer switches. */
- ctl.dev = EAP_OUTPUT_SELECT;
- ctl.type = AUDIO_MIXER_SET;
- ctl.un.mask = 1 << EAP_VOICE_VOL | 1 << EAP_FM_VOL | 1 << EAP_CD_VOL |
- 1 << EAP_LINE_VOL | 1 << EAP_AUX_VOL | 1 << EAP_MIC_VOL;
- eap_mixer_set_port(sc, &ctl);
-
- ctl.type = AUDIO_MIXER_VALUE;
- ctl.un.value.num_channels = 1;
- for (ctl.dev = EAP_MASTER_VOL; ctl.dev < EAP_MIC_VOL; ctl.dev++) {
- ctl.un.value.level[AUDIO_MIXER_LEVEL_MONO] = VOL_0DB;
- eap_mixer_set_port(sc, &ctl);
- }
- ctl.un.value.level[AUDIO_MIXER_LEVEL_MONO] = 0;
- eap_mixer_set_port(sc, &ctl); /* set the mic to 0 */
- ctl.dev = EAP_MIC_PREAMP;
- ctl.type = AUDIO_MIXER_ENUM;
- ctl.un.ord = 0;
- eap_mixer_set_port(sc, &ctl);
- ctl.dev = EAP_RECORD_SOURCE;
- ctl.type = AUDIO_MIXER_SET;
- ctl.un.mask = 1 << EAP_MIC_VOL;
- eap_mixer_set_port(sc, &ctl);
-
- audio_attach_mi(&eap_hw_if, sc, &sc->sc_dev);
+ printf(": %s\n", sc->sc_dev.dv_xname, intrstr);
+
+ if (!sc->sc_1371) {
+ /* Enable interrupts and looping mode. */
+ /* enable the parts we need */
+ EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
+ EWRITE4(sc, EAP_ICSC, EAP_CDC_EN);
+
+ /* reset codec */
+ /* normal operation */
+ /* select codec clocks */
+ eap_write_codec(sc, AK_RESET, AK_PD);
+ eap_write_codec(sc, AK_RESET, AK_PD | AK_NRST);
+ eap_write_codec(sc, AK_CS, 0x0);
+
+ eap_hw_if.query_devinfo = eap_query_devinfo;
+ eap_hw_if.set_port = eap_mixer_set_port;
+ eap_hw_if.get_port = eap_mixer_get_port;
+
+ /* Enable all relevant mixer switches. */
+ ctl.dev = EAP_OUTPUT_SELECT;
+ ctl.type = AUDIO_MIXER_SET;
+ ctl.un.mask = 1 << EAP_VOICE_VOL | 1 << EAP_FM_VOL |
+ 1 << EAP_CD_VOL | 1 << EAP_LINE_VOL | 1 << EAP_AUX_VOL |
+ 1 << EAP_MIC_VOL;
+ eap_hw_if.set_port(sc, &ctl);
+
+ ctl.type = AUDIO_MIXER_VALUE;
+ ctl.un.value.num_channels = 1;
+ for (ctl.dev = EAP_MASTER_VOL; ctl.dev < EAP_MIC_VOL;
+ ctl.dev++) {
+ ctl.un.value.level[AUDIO_MIXER_LEVEL_MONO] = VOL_0DB;
+ eap_hw_if.set_port(sc, &ctl);
+ }
+ ctl.un.value.level[AUDIO_MIXER_LEVEL_MONO] = 0;
+ eap_hw_if.set_port(sc, &ctl);
+ ctl.dev = EAP_MIC_PREAMP;
+ ctl.type = AUDIO_MIXER_ENUM;
+ ctl.un.ord = 0;
+ eap_hw_if.set_port(sc, &ctl);
+ ctl.dev = EAP_RECORD_SOURCE;
+ ctl.type = AUDIO_MIXER_SET;
+ ctl.un.mask = 1 << EAP_MIC_VOL;
+ eap_hw_if.set_port(sc, &ctl);
+ } else {
+ int error;
+
+ /* clean slate */
+ EWRITE4(sc, EAP_SIC, 0);
+ EWRITE4(sc, EAP_ICSC, 0);
+ EWRITE4(sc, E1371_LEGACY, 0);
+
+ /* Reset from es1371's perspective */
+ EWRITE4(sc, EAP_ICSC, E1371_SYNC_RES);
+ delay(20);
+ EWRITE4(sc, EAP_ICSC, 0);
+
+ /* must properly reprogram sample rate converter,
+ * or it locks up. Set some defaults for the life of the
+ * machine, and set up a sb default sample rate.
+ */
+ EWRITE4(sc, E1371_SRC, E1371_SRC_DISABLE);
+ for (i=0; i<0x80; i++)
+ eap1371_src_write(sc, i, 0);
+ eap1371_src_write(sc, ESRC_DAC1+ESRC_TRUNC_N, ESRC_SET_N(16));
+ eap1371_src_write(sc, ESRC_DAC2+ESRC_TRUNC_N, ESRC_SET_N(16));
+ eap1371_src_write(sc, ESRC_DAC1+ESRC_IREGS, ESRC_SET_VFI(16));
+ eap1371_src_write(sc, ESRC_DAC2+ESRC_IREGS, ESRC_SET_VFI(16));
+ eap1371_src_write(sc, ESRC_ADC_VOLL, ESRC_SET_ADC_VOL(16));
+ eap1371_src_write(sc, ESRC_ADC_VOLR, ESRC_SET_ADC_VOL(16));
+ eap1371_src_write(sc, ESRC_DAC1_VOLL, ESRC_SET_DAC_VOLI(1));
+ eap1371_src_write(sc, ESRC_DAC1_VOLR, ESRC_SET_DAC_VOLI(1));
+ eap1371_src_write(sc, ESRC_DAC2_VOLL, ESRC_SET_DAC_VOLI(1));
+ eap1371_src_write(sc, ESRC_DAC2_VOLR, ESRC_SET_DAC_VOLI(1));
+ eap1371_set_adc_rate(sc, 22050);
+ eap1371_set_dac_rate(sc, 22050, 1);
+ eap1371_set_dac_rate(sc, 22050, 2);
+
+ EWRITE4(sc, E1371_SRC, 0);
+
+ /* Reset codec */
+
+ /* Interrupt enable */
+ sc->host_if.arg = sc;
+ sc->host_if.attach = eap1371_attach_codec;
+ sc->host_if.read = eap1371_read_codec;
+ sc->host_if.write = eap1371_write_codec;
+ sc->host_if.reset = eap1371_reset_codec;
+
+ if ((error = ac97_attach(&sc->host_if)) == 0) {
+ /* Interrupt enable */
+ EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
+ } else
+ return;
+
+ eap_hw_if.query_devinfo = eap1371_query_devinfo;
+ eap_hw_if.set_port = eap1371_mixer_set_port;
+ eap_hw_if.get_port = eap1371_mixer_get_port;
+
+ /* Just enable the DAC and master volumes by default */
+ ctl.type = AUDIO_MIXER_ENUM;
+ ctl.un.ord = 0; /* off */
+ ctl.dev = eap1371_get_portnum_by_name(sc, AudioCoutputs,
+ AudioNmaster, AudioNmute);
+ eap1371_mixer_set_port(sc, &ctl);
+ ctl.dev = eap1371_get_portnum_by_name(sc, AudioCinputs,
+ AudioNdac, AudioNmute);
+ eap1371_mixer_set_port(sc, &ctl);
+ ctl.dev = eap1371_get_portnum_by_name(sc, AudioCrecord,
+ AudioNvolume, AudioNmute);
+ eap1371_mixer_set_port(sc, &ctl);
+
+
+ ctl.dev = eap1371_get_portnum_by_name(sc, AudioCrecord,
+ AudioNsource, NULL);
+ ctl.type = AUDIO_MIXER_ENUM;
+ ctl.un.ord = 0;
+ eap1371_mixer_set_port(sc, &ctl);
+
+ }
+
+ audio_attach_mi(&eap_hw_if, sc, &sc->sc_dev);
+}
+
+int
+eap1371_attach_codec(sc_, codec_if)
+ void *sc_;
+ struct ac97_codec_if *codec_if;
+{
+ struct eap_softc *sc = sc_;
+
+ sc->codec_if = codec_if;
+ return (0);
+}
+
+void
+eap1371_reset_codec(sc_)
+ void *sc_;
+{
+ struct eap_softc *sc = sc_;
+ u_int32_t icsc = EREAD4(sc, EAP_ICSC);
+
+ EWRITE4(sc, EAP_ICSC, icsc | E1371_SYNC_RES);
+ delay(100);
+ EWRITE4(sc, EAP_ICSC, icsc & ~E1371_SYNC_RES);
+
+ return;
}
int
@@ -586,7 +959,6 @@ eap_open(addr, flags)
void *addr;
int flags;
{
-
return (0);
}
@@ -673,21 +1045,24 @@ eap_set_params(addr, setmode, usemode, play, rec)
{
struct eap_softc *sc = addr;
struct audio_params *p;
- u_int32_t mode, div;
+ int mode;
+ u_int32_t div;
/*
- * This device only has one clock, so make the sample rates match.
+ * The es1370 only has one clock, so make the sample rates match.
*/
- if (play->sample_rate != rec->sample_rate &&
- usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
- if (setmode == AUMODE_PLAY) {
- rec->sample_rate = play->sample_rate;
- setmode |= AUMODE_RECORD;
+ if (!sc->sc_1371) {
+ if (play->sample_rate != rec->sample_rate &&
+ usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
+ if (setmode == AUMODE_PLAY) {
+ rec->sample_rate = play->sample_rate;
+ setmode |= AUMODE_RECORD;
} else if (setmode == AUMODE_RECORD) {
- play->sample_rate = rec->sample_rate;
- setmode |= AUMODE_PLAY;
+ play->sample_rate = rec->sample_rate;
+ setmode |= AUMODE_PLAY;
} else
- return (EINVAL);
+ return (EINVAL);
+ }
}
for (mode = AUMODE_RECORD; mode != -1;
@@ -697,7 +1072,7 @@ eap_set_params(addr, setmode, usemode, play, rec)
p = mode == AUMODE_PLAY ? play : rec;
- if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
+ if (p->sample_rate < 4000 || p->sample_rate > 48000 ||
(p->precision != 8 && p->precision != 16) ||
(p->channels != 1 && p->channels != 2))
return (EINVAL);
@@ -746,22 +1121,31 @@ eap_set_params(addr, setmode, usemode, play, rec)
}
}
- /* Set the speed */
- DPRINTFN(2, ("eap_set_params: old ICSC = 0x%08x\n",
- EREAD4(sc, EAP_ICSC)));
- div = EREAD4(sc, EAP_ICSC) & ~EAP_PCLKBITS;
- /*
- * XXX
- * The -2 isn't documented, but seemed to make the wall time match
- * what I expect. - mycroft
- */
- if (usemode == AUMODE_RECORD)
- div |= EAP_SET_PCLKDIV(EAP_XTAL_FREQ / rec->sample_rate - 2);
- else
- div |= EAP_SET_PCLKDIV(EAP_XTAL_FREQ / play->sample_rate - 2);
- div |= EAP_CCB_INTRM;
- EWRITE4(sc, EAP_ICSC, div);
- DPRINTFN(2, ("eap_set_params: set ICSC = 0x%08x\n", div));
+ if (sc->sc_1371) {
+ eap1371_set_dac_rate(sc, play->sample_rate, 1);
+ eap1371_set_dac_rate(sc, play->sample_rate, 2);
+ eap1371_set_adc_rate(sc, rec->sample_rate);
+ } else {
+ /* Set the speed */
+ DPRINTFN(2, ("eap_set_params: old ICSC = 0x%08x\n",
+ EREAD4(sc, EAP_ICSC)));
+ div = EREAD4(sc, EAP_ICSC) & ~EAP_PCLKBITS;
+ /*
+ * XXX
+ * The -2 isn't documented, but seemed to make the wall
+ * time match
+ * what I expect. - mycroft
+ */
+ if (usemode == AUMODE_RECORD)
+ div |= EAP_SET_PCLKDIV(EAP_XTAL_FREQ /
+ rec->sample_rate - 2);
+ else
+ div |= EAP_SET_PCLKDIV(EAP_XTAL_FREQ /
+ play->sample_rate - 2);
+ div |= EAP_CCB_INTRM;
+ EWRITE4(sc, EAP_ICSC, div);
+ DPRINTFN(2, ("eap_set_params: set ICSC = 0x%08x\n", div));
+ }
return (0);
}
@@ -785,7 +1169,7 @@ eap_trigger_output(addr, start, end, blksize, intr, arg, param)
{
struct eap_softc *sc = addr;
struct eap_dma *p;
- u_int32_t mode;
+ u_int32_t icsc, sic;
int sampshift;
#ifdef DIAGNOSTIC
@@ -794,23 +1178,27 @@ eap_trigger_output(addr, start, end, blksize, intr, arg, param)
sc->sc_prun = 1;
#endif
- DPRINTFN(1, ("eap_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
- addr, start, end, blksize, intr, arg));
+ DPRINTFN(1, ("eap_trigger_output: sc=%p start=%p end=%p "
+ "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
sc->sc_pintr = intr;
sc->sc_parg = arg;
- mode = EREAD4(sc, EAP_SIC) & ~(EAP_P2_S_EB | EAP_P2_S_MB | EAP_INC_BITS);
- mode |= EAP_SET_P2_ST_INC(0) | EAP_SET_P2_END_INC(param->precision * param->factor / 8);
+ icsc = EREAD4(sc, EAP_ICSC);
+ EWRITE4(sc, EAP_ICSC, icsc & ~EAP_DAC2_EN);
+
+ sic = EREAD4(sc, EAP_SIC);
+ sic &= ~(EAP_P2_S_EB | EAP_P2_S_MB | EAP_INC_BITS);
+ sic |= EAP_SET_P2_ST_INC(0) | EAP_SET_P2_END_INC(param->precision * param->factor / 8);
sampshift = 0;
if (param->precision * param->factor == 16) {
- mode |= EAP_P2_S_EB;
+ sic |= EAP_P2_S_EB;
sampshift++;
}
if (param->channels == 2) {
- mode |= EAP_P2_S_MB;
+ sic |= EAP_P2_S_MB;
sampshift++;
}
- EWRITE4(sc, EAP_SIC, mode);
+ EWRITE4(sc, EAP_SIC, sic);
for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
;
@@ -820,17 +1208,18 @@ eap_trigger_output(addr, start, end, blksize, intr, arg, param)
}
DPRINTF(("eap_trigger_output: DAC2_ADDR=0x%x, DAC2_SIZE=0x%x\n",
- (int)DMAADDR(p), EAP_SET_SIZE(0, ((end - start) >> 2) - 1)));
+ (int)DMAADDR(p),
+ EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1)));
EWRITE4(sc, EAP_MEMPAGE, EAP_DAC_PAGE);
EWRITE4(sc, EAP_DAC2_ADDR, DMAADDR(p));
- EWRITE4(sc, EAP_DAC2_SIZE, EAP_SET_SIZE(0, ((end - start) >> 2) - 1));
+ EWRITE4(sc, EAP_DAC2_SIZE,
+ EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1));
EWRITE2(sc, EAP_DAC2_CSR, (blksize >> sampshift) - 1);
- mode = EREAD4(sc, EAP_ICSC) & ~EAP_DAC2_EN;
- EWRITE4(sc, EAP_ICSC, mode);
- mode |= EAP_DAC2_EN;
- EWRITE4(sc, EAP_ICSC, mode);
- DPRINTFN(1, ("eap_trigger_output: set ICSC = 0x%08x\n", mode));
+
+ EWRITE4(sc, EAP_ICSC, icsc | EAP_DAC2_EN);
+
+ DPRINTFN(1, ("eap_trigger_output: set ICSC = 0x%08x\n", icsc));
return (0);
}
@@ -846,7 +1235,7 @@ eap_trigger_input(addr, start, end, blksize, intr, arg, param)
{
struct eap_softc *sc = addr;
struct eap_dma *p;
- u_int32_t mode;
+ u_int32_t icsc, sic;
int sampshift;
#ifdef DIAGNOSTIC
@@ -860,17 +1249,21 @@ eap_trigger_input(addr, start, end, blksize, intr, arg, param)
sc->sc_rintr = intr;
sc->sc_rarg = arg;
- mode = EREAD4(sc, EAP_SIC) & ~(EAP_R1_S_EB | EAP_R1_S_MB);
+ icsc = EREAD4(sc, EAP_ICSC);
+ EWRITE4(sc, EAP_ICSC, icsc & ~EAP_ADC_EN);
+
+ sic = EREAD4(sc, EAP_SIC);
+ sic &= ~(EAP_R1_S_EB | EAP_R1_S_MB);
sampshift = 0;
if (param->precision * param->factor == 16) {
- mode |= EAP_R1_S_EB;
+ sic |= EAP_R1_S_EB;
sampshift++;
}
if (param->channels == 2) {
- mode |= EAP_R1_S_MB;
+ sic |= EAP_R1_S_MB;
sampshift++;
}
- EWRITE4(sc, EAP_SIC, mode);
+ EWRITE4(sc, EAP_SIC, sic);
for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
;
@@ -880,17 +1273,18 @@ eap_trigger_input(addr, start, end, blksize, intr, arg, param)
}
DPRINTF(("eap_trigger_input: ADC_ADDR=0x%x, ADC_SIZE=0x%x\n",
- (int)DMAADDR(p), EAP_SET_SIZE(0, ((end - start) >> 2) - 1)));
+ (int)DMAADDR(p),
+ EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1)));
EWRITE4(sc, EAP_MEMPAGE, EAP_ADC_PAGE);
EWRITE4(sc, EAP_ADC_ADDR, DMAADDR(p));
- EWRITE4(sc, EAP_ADC_SIZE, EAP_SET_SIZE(0, ((end - start) >> 2) - 1));
+ EWRITE4(sc, EAP_ADC_SIZE,
+ EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1));
EWRITE2(sc, EAP_ADC_CSR, (blksize >> sampshift) - 1);
- mode = EREAD4(sc, EAP_ICSC) & ~EAP_ADC_EN;
- EWRITE4(sc, EAP_ICSC, mode);
- mode |= EAP_ADC_EN;
- EWRITE4(sc, EAP_ICSC, mode);
- DPRINTFN(1, ("eap_trigger_input: set ICSC = 0x%08x\n", mode));
+
+ EWRITE4(sc, EAP_ICSC, icsc | EAP_ADC_EN);
+
+ DPRINTFN(1, ("eap_trigger_input: set ICSC = 0x%08x\n", icsc));
return (0);
}
@@ -900,11 +1294,11 @@ eap_halt_output(addr)
void *addr;
{
struct eap_softc *sc = addr;
- u_int32_t mode;
+ u_int32_t icsc;
DPRINTF(("eap: eap_halt_output\n"));
- mode = EREAD4(sc, EAP_ICSC) & ~EAP_DAC2_EN;
- EWRITE4(sc, EAP_ICSC, mode);
+ icsc = EREAD4(sc, EAP_ICSC);
+ EWRITE4(sc, EAP_ICSC, icsc & ~EAP_DAC2_EN);
#ifdef DIAGNOSTIC
sc->sc_prun = 0;
#endif
@@ -916,11 +1310,11 @@ eap_halt_input(addr)
void *addr;
{
struct eap_softc *sc = addr;
- u_int32_t mode;
+ u_int32_t icsc;
DPRINTF(("eap: eap_halt_input\n"));
- mode = EREAD4(sc, EAP_ICSC) & ~EAP_ADC_EN;
- EWRITE4(sc, EAP_ICSC, mode);
+ icsc = EREAD4(sc, EAP_ICSC);
+ EWRITE4(sc, EAP_ICSC, icsc & ~EAP_ADC_EN);
#ifdef DIAGNOSTIC
sc->sc_rrun = 0;
#endif
@@ -936,15 +1330,57 @@ eap_getdev(addr, retp)
return (0);
}
+int
+eap1371_mixer_set_port(addr, cp)
+ void *addr;
+ mixer_ctrl_t *cp;
+{
+ struct eap_softc *sc = addr;
+
+ return ((sc->codec_if->vtbl->mixer_set_port)(sc->codec_if,
+ cp));
+}
+
+int
+eap1371_mixer_get_port(addr, cp)
+ void *addr;
+ mixer_ctrl_t *cp;
+{
+ struct eap_softc *sc = addr;
+
+ return ((sc->codec_if->vtbl->mixer_get_port)(sc->codec_if,
+ cp));
+}
+
+int
+eap1371_query_devinfo(addr, dip)
+ void *addr;
+ mixer_devinfo_t *dip;
+{
+ struct eap_softc *sc = addr;
+
+ return ((sc->codec_if->vtbl->query_devinfo)(sc->codec_if, dip));
+}
+
+int
+eap1371_get_portnum_by_name(sc, class, device, qualifier)
+ struct eap_softc *sc;
+ char *class, *device, *qualifier;
+{
+ return ((sc->codec_if->vtbl->get_portnum_by_name)(sc->codec_if, class,
+ device, qualifier));
+}
+
void
eap_set_mixer(sc, a, d)
struct eap_softc *sc;
int a, d;
{
eap_write_codec(sc, a, d);
- DPRINTFN(1, ("eap_mixer_set_port port 0x%02x = 0x%02x\n", a, d));
-}
+ sc->sc_port[a] = d;
+ DPRINTFN(1, ("eap_mixer_set_port port 0x%02x = 0x%02x\n", a, d));
+}
int
eap_mixer_set_port(addr, cp)
@@ -1057,10 +1493,8 @@ eap_mixer_set_port(addr, cp)
return (EINVAL);
}
eap_set_mixer(sc, la, l);
- sc->sc_port[la] = l;
if (ra >= 0) {
eap_set_mixer(sc, ra, r);
- sc->sc_port[ra] = r;
}
return (0);
}
@@ -1278,8 +1712,7 @@ void *
eap_malloc(addr, size, pool, flags)
void *addr;
u_long size;
- int pool;
- int flags;
+ int pool, flags;
{
struct eap_softc *sc = addr;
struct eap_dma *p;
@@ -1318,7 +1751,7 @@ eap_free(addr, ptr, pool)
}
u_long
-eap_round(addr, size)
+eap_round_buffersize(addr, size)
void *addr;
u_long size;
{
@@ -1335,6 +1768,8 @@ eap_mappage(addr, mem, off, prot)
struct eap_softc *sc = addr;
struct eap_dma *p;
+ if (off < 0)
+ return (-1);
for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next)
;
if (!p)
@@ -1347,5 +1782,6 @@ int
eap_get_props(addr)
void *addr;
{
- return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX);
+ return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
+ AUDIO_PROP_FULLDUPLEX);
}