summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/eap.c715
1 files changed, 407 insertions, 308 deletions
diff --git a/sys/dev/pci/eap.c b/sys/dev/pci/eap.c
index 054df49c083..1f89c81517e 100644
--- a/sys/dev/pci/eap.c
+++ b/sys/dev/pci/eap.c
@@ -1,13 +1,14 @@
-/* $NetBSD: eap.c,v 1.6 1998/05/26 13:28:03 augustss Exp $ */
+/* $OpenBSD: eap.c,v 1.2 1998/10/28 18:06:46 downsj Exp $ */
+/* $NetBSD: eap.c,v 1.17 1998/08/25 04:56:01 thorpej Exp $ */
/*
* Copyright (c) 1998 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>
- * Charles Hannum <mycroft@netbsd.org>
* Testing: Chuck Cranor <chuck@maria.wustl.edu>
* Phil Nelson <phil@cs.wwu.edu>
*
@@ -64,13 +65,13 @@
#include <machine/bus.h>
-/* NetBSD 1.3 backwards compatibility */
#ifndef BUS_DMA_COHERENT
#define BUS_DMA_COHERENT 0 /* XXX */
+#endif
+
struct cfdriver eap_cd = {
NULL, "eap", DV_DULL
};
-#endif
#define PCI_CBIO 0x10
@@ -126,7 +127,6 @@ struct cfdriver eap_cd = {
#define EAP_P2_S_EB 0x00000008
#define EAP_R1_S_MB 0x00000010
#define EAP_R1_S_EB 0x00000020
-#define EAP_R1P2_BITS 0x0000003c
#define EAP_P2_DAC_SEN 0x00000040
#define EAP_P1_SCT_RLD 0x00000080
#define EAP_P1_INTR_EN 0x00000100
@@ -228,38 +228,36 @@ struct cfdriver eap_cd = {
#define EAP_AUX_VOL 5
#define EAP_MIC_VOL 6
#define EAP_RECORD_SOURCE 7
-#define EAP_OUTPUT_CLASS 8
-#define EAP_RECORD_CLASS 9
-#define EAP_INPUT_CLASS 10
-
-#define EAP_NDEVS 11
-
+#define EAP_OUTPUT_SELECT 8
+#define EAP_MIC_PREAMP 9
+#define EAP_OUTPUT_CLASS 10
+#define EAP_RECORD_CLASS 11
+#define EAP_INPUT_CLASS 12
#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
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif
-#define __BROKEN_INDIRECT_CONFIG
-#ifdef __BROKEN_INDIRECT_CONFIG
int eap_match __P((struct device *, void *, void *));
-#else
-int eap_match __P((struct device *, struct cfdata *, void *));
-#endif
void eap_attach __P((struct device *, struct device *, void *));
int eap_intr __P((void *));
struct eap_dma {
bus_dmamap_t map;
- caddr_t addr;
- bus_dma_segment_t segs[1];
- int nsegs;
- size_t size;
- struct eap_dma *next;
+ caddr_t addr;
+ bus_dma_segment_t segs[1];
+ int nsegs;
+ size_t size;
+ struct eap_dma *next;
};
#define DMAADDR(map) ((map)->segs[0].ds_addr)
#define KERNADDR(map) ((void *)((map)->addr))
@@ -271,20 +269,24 @@ struct eap_softc {
bus_space_handle_t ioh;
bus_dma_tag_t sc_dmatag; /* DMA tag */
- struct eap_dma *sc_dmas;
+ struct eap_dma *sc_dmas;
void (*sc_pintr)(void *); /* dma completion intr handler */
void *sc_parg; /* arg for sc_intr() */
+#ifdef DIAGNOSTIC
char sc_prun;
+#endif
void (*sc_rintr)(void *); /* dma completion intr handler */
void *sc_rarg; /* arg for sc_intr() */
+#ifdef DIAGNOSTIC
char sc_rrun;
-
- int sc_sampsize; /* bytes / sample */
+#endif
u_char sc_port[AK_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;
};
int eap_allocmem __P((struct eap_softc *, size_t, size_t, struct eap_dma *));
@@ -304,12 +306,12 @@ void eap_close __P((void *));
int eap_query_encoding __P((void *, struct audio_encoding *));
int eap_set_params __P((void *, int, int, struct audio_params *, struct audio_params *));
int eap_round_blocksize __P((void *, int));
-int eap_dma_init_output __P((void *, void *, int));
-int eap_dma_init_input __P((void *, void *, int));
-int eap_dma_output __P((void *, void *, int, void (*)(void *), void*));
-int eap_dma_input __P((void *, void *, int, void (*)(void *), void*));
-int eap_halt_in_dma __P((void *));
-int eap_halt_out_dma __P((void *));
+int eap_trigger_output __P((void *, void *, void *, int, void (*)(void *),
+ void *, struct audio_params *));
+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 *));
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 *));
@@ -330,12 +332,12 @@ struct audio_hw_if eap_hw_if = {
eap_set_params,
eap_round_blocksize,
NULL,
- eap_dma_init_output,
- eap_dma_init_input,
- eap_dma_output,
- eap_dma_input,
- eap_halt_out_dma,
- eap_halt_in_dma,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ eap_halt_output,
+ eap_halt_input,
NULL,
eap_getdev,
NULL,
@@ -347,6 +349,10 @@ struct audio_hw_if eap_hw_if = {
eap_round,
eap_mappage,
eap_get_props,
+#ifdef notyet
+ eap_trigger_output,
+ eap_trigger_input,
+#endif
};
struct audio_device eap_device = {
@@ -358,12 +364,7 @@ struct audio_device eap_device = {
int
eap_match(parent, match, aux)
struct device *parent;
-#ifdef __BROKEN_INDIRECT_CONFIG
- void *match;
-#else
- struct cfdata *match;
-#endif
- void *aux;
+ void *match, *aux;
{
struct pci_attach_args *pa = (struct pci_attach_args *) aux;
@@ -381,12 +382,18 @@ eap_write_codec(sc, a, d)
int a, d;
{
int icss;
+ int timeo = 512;
do {
- icss = EREAD4(sc, EAP_ICSS);
+ icss = EREAD4(sc, EAP_ICSS);
+ if (!(icss & EAP_CSTAT)) {
+ EWRITE4(sc, EAP_CODEC, EAP_SET_CODEC(a, d));
+ return;
+ }
DPRINTFN(5,("eap: codec %d prog: icss=0x%08x\n", a, icss));
- } while(icss & EAP_CWRIP);
- EWRITE4(sc, EAP_CODEC, EAP_SET_CODEC(a, d));
+ timeo--;
+ } while(timeo > 0);
+ DPRINTF(("eap: codec write timeout, %d prog: icss=0x%08x\n", a, icss));
}
void
@@ -403,24 +410,15 @@ eap_attach(parent, self, aux)
bus_size_t iosize;
pci_intr_handle_t ih;
pcireg_t csr;
- char devinfo[256];
mixer_ctrl_t ctl;
- pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
- printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
-
/* Map I/O register */
if (pci_io_find(pc, pa->pa_tag, PCI_CBIO, &iobase, &iosize)) {
- printf("%s: can't find i/o base\n", sc->sc_dev.dv_xname);
+ printf("\n%s: can't find i/o base\n", sc->sc_dev.dv_xname);
return;
}
-#if defined(__OpenBSD__)
if (bus_space_map(sc->iot, iobase, iosize, 0, &sc->ioh)) {
-#else
- if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
- &sc->iot, &sc->ioh, NULL, NULL)) {
-#endif
- printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
+ printf("\n%s: can't map i/o space\n", sc->sc_dev.dv_xname);
return;
}
@@ -434,38 +432,37 @@ 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)) {
- printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
+ 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);
if (sc->sc_ih == NULL) {
- printf("%s: couldn't establish interrupt",
+ printf("\n%s: couldn't establish interrupt",
sc->sc_dev.dv_xname);
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
return;
}
- printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+ printf(": interrupting at %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 */
+ EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
+ EWRITE4(sc, EAP_ICSC, EAP_CDC_EN|EAP_SERR_DISABLE|EAP_SET_PCLKDIV(EAP_XTAL_FREQ / 8000)); /* 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. */
- eap_write_codec(sc, AK_OUT_MIXER1,
- AK_M_FM_L | AK_M_FM_R |
- AK_M_LINE_L | AK_M_LINE_R |
- AK_M_CD_L | AK_M_CD_R);
- eap_write_codec(sc, AK_OUT_MIXER2,
- AK_M_AUX_L | AK_M_AUX_R |
- AK_M_VOICE_L | AK_M_VOICE_R |
- AK_M_MONO2 | AK_M_MONO1);
+ 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++) {
@@ -474,6 +471,10 @@ eap_attach(parent, self, aux)
}
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;
@@ -489,43 +490,43 @@ eap_intr(p)
struct eap_softc *sc = p;
u_int32_t intr, sic;
- intr = EREAD4(sc, EAP_ICSS);
- if (!(intr & EAP_INTR))
- return (0);
+ intr = EREAD4(sc, EAP_ICSS);
+ if (!(intr & EAP_INTR))
+ return (0);
sic = EREAD4(sc, EAP_SIC);
DPRINTFN(5, ("eap_intr: ICSS=0x%08x, SIC=0x%08x\n", intr, sic));
- if (intr & EAP_I_ADC) {
- /*
- * XXX This is a hack!
- * The EAP chip sometimes generates the recording interrupt
- * while it is still transferring the data. To make sure
- * it has all arrived we busy wait until the count is right.
- * The transfer we are waiting for is 8 longwords.
- */
- int s, nw, n;
- EWRITE4(sc, EAP_MEMPAGE, EAP_ADC_PAGE);
- s = EREAD4(sc, EAP_ADC_CSR);
- nw = ((s & 0xffff) + 1) / 4; /* # of words in DMA */
- n = 0;
- while (((EREAD4(sc, EAP_ADC_SIZE) >> 16) + 8) % nw == 0) {
- delay(10);
- if (++n > 100) {
- printf("eapintr: dma fix timeout");
- break;
- }
- }
- /* Continue with normal interrupt handling. */
+ if (intr & EAP_I_ADC) {
+ /*
+ * XXX This is a hack!
+ * The EAP chip sometimes generates the recording interrupt
+ * while it is still transferring the data. To make sure
+ * it has all arrived we busy wait until the count is right.
+ * The transfer we are waiting for is 8 longwords.
+ */
+ int s, nw, n;
+ EWRITE4(sc, EAP_MEMPAGE, EAP_ADC_PAGE);
+ s = EREAD4(sc, EAP_ADC_CSR);
+ nw = ((s & 0xffff) + 1) >> 2; /* # of words in DMA */
+ n = 0;
+ while (((EREAD4(sc, EAP_ADC_SIZE) >> 16) + 8) % nw == 0) {
+ delay(10);
+ if (++n > 100) {
+ printf("eapintr: dma fix timeout");
+ break;
+ }
+ }
+ /* Continue with normal interrupt handling. */
EWRITE4(sc, EAP_SIC, sic & ~EAP_R1_INTR_EN);
EWRITE4(sc, EAP_SIC, sic);
- if (sc->sc_rintr)
- sc->sc_rintr(sc->sc_rarg);
- }
- if (intr & EAP_I_DAC2) {
+ if (sc->sc_rintr)
+ sc->sc_rintr(sc->sc_rarg);
+ }
+ if (intr & EAP_I_DAC2) {
EWRITE4(sc, EAP_SIC, sic & ~EAP_P2_INTR_EN);
EWRITE4(sc, EAP_SIC, sic);
- if (sc->sc_pintr)
- sc->sc_pintr(sc->sc_parg);
- }
+ if (sc->sc_pintr)
+ sc->sc_pintr(sc->sc_parg);
+ }
return (1);
}
@@ -534,7 +535,7 @@ eap_allocmem(sc, size, align, p)
struct eap_softc *sc;
size_t size;
size_t align;
- struct eap_dma *p;
+ struct eap_dma *p;
{
int error;
@@ -573,7 +574,7 @@ free:
int
eap_freemem(sc, p)
struct eap_softc *sc;
- struct eap_dma *p;
+ struct eap_dma *p;
{
bus_dmamap_unload(sc->sc_dmatag, p->map);
bus_dmamap_destroy(sc->sc_dmatag, p->map);
@@ -587,14 +588,8 @@ eap_open(addr, flags)
void *addr;
int flags;
{
- struct eap_softc *sc = addr;
-
- DPRINTF(("eap_open: sc=%p\n", sc));
-
- sc->sc_pintr = 0;
- sc->sc_rintr = 0;
- return (0);
+ return (0);
}
/*
@@ -606,11 +601,11 @@ eap_close(addr)
{
struct eap_softc *sc = addr;
- eap_halt_in_dma(sc);
- eap_halt_out_dma(sc);
+ eap_halt_output(sc);
+ eap_halt_input(sc);
- sc->sc_pintr = 0;
- sc->sc_rintr = 0;
+ sc->sc_pintr = 0;
+ sc->sc_rintr = 0;
}
int
@@ -643,7 +638,7 @@ eap_query_encoding(addr, fp)
fp->precision = 8;
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
return (0);
- case 4:
+ case 4:
strcpy(fp->name, AudioEslinear_le);
fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
fp->precision = 16;
@@ -673,81 +668,104 @@ eap_query_encoding(addr, fp)
}
int
-eap_set_params(addr, setmode, usemode, p, r)
+eap_set_params(addr, setmode, usemode, play, rec)
void *addr;
int setmode, usemode;
- struct audio_params *p, *r;
+ struct audio_params *play, *rec;
{
struct eap_softc *sc = addr;
- void (*pswcode) __P((void *, u_char *buf, int cnt));
- void (*rswcode) __P((void *, u_char *buf, int cnt));
- u_int32_t mode, div;
-
-
- pswcode = rswcode = 0;
- switch (p->encoding) {
- case AUDIO_ENCODING_SLINEAR_BE:
- if (p->precision == 16)
- rswcode = pswcode = swap_bytes;
- else
- pswcode = rswcode = change_sign8;
- break;
- case AUDIO_ENCODING_SLINEAR_LE:
- if (p->precision != 16)
- pswcode = rswcode = change_sign8;
- break;
- case AUDIO_ENCODING_ULINEAR_BE:
- if (p->precision == 16) {
- pswcode = swap_bytes_change_sign16;
- rswcode = change_sign16_swap_bytes;
- }
- break;
- case AUDIO_ENCODING_ULINEAR_LE:
- if (p->precision == 16)
- pswcode = rswcode = change_sign16;
- break;
- case AUDIO_ENCODING_ULAW:
- pswcode = mulaw_to_ulinear8;
- rswcode = ulinear8_to_mulaw;
- break;
- case AUDIO_ENCODING_ALAW:
- pswcode = alaw_to_ulinear8;
- rswcode = ulinear8_to_alaw;
- break;
- default:
- return (EINVAL);
- }
- if (p->precision == 16)
- mode = EAP_P2_S_EB | EAP_R1_S_EB;
- else
- mode = 0;
- if (p->channels == 2)
- mode |= EAP_P2_S_MB | EAP_R1_S_MB;
- else if (p->channels != 1)
- return (EINVAL);
- if (p->sample_rate < 4000 || p->sample_rate > 50000)
- return (EINVAL);
+ struct audio_params *p;
+ u_int32_t mode, div;
+
+ /*
+ * This device 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;
+ } else if (setmode == AUMODE_RECORD) {
+ play->sample_rate = rec->sample_rate;
+ setmode |= AUMODE_PLAY;
+ } else
+ return (EINVAL);
+ }
- sc->sc_sampsize = p->precision / 8 * p->channels; /* bytes / sample */
- p->sw_code = pswcode;
- r->sw_code = rswcode;
+ for (mode = AUMODE_RECORD; mode != -1;
+ mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
+ if ((setmode & mode) == 0)
+ continue;
- /* Set the encoding */
- mode |= EREAD4(sc, EAP_SIC) & ~(EAP_R1P2_BITS | EAP_INC_BITS);
- mode |= EAP_SET_P2_ST_INC(0) | EAP_SET_P2_END_INC(p->precision / 8);
- EWRITE4(sc, EAP_SIC, mode);
- DPRINTFN(2, ("eap_set_params: set SIC = 0x%08x\n", mode));
+ p = mode == AUMODE_PLAY ? play : rec;
- /* Set the speed */
+ if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
+ (p->precision != 8 && p->precision != 16) ||
+ (p->channels != 1 && p->channels != 2))
+ return (EINVAL);
+
+ p->factor = 1;
+ p->sw_code = 0;
+ switch (p->encoding) {
+ case AUDIO_ENCODING_SLINEAR_BE:
+ if (p->precision == 16)
+ p->sw_code = swap_bytes;
+ else
+ p->sw_code = change_sign8;
+ break;
+ case AUDIO_ENCODING_SLINEAR_LE:
+ if (p->precision != 16)
+ p->sw_code = change_sign8;
+ break;
+ case AUDIO_ENCODING_ULINEAR_BE:
+ if (p->precision == 16) {
+ if (mode == AUMODE_PLAY)
+ p->sw_code = swap_bytes_change_sign16;
+ else
+ p->sw_code = change_sign16_swap_bytes;
+ }
+ break;
+ case AUDIO_ENCODING_ULINEAR_LE:
+ if (p->precision == 16)
+ p->sw_code = change_sign16;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ if (mode == AUMODE_PLAY) {
+ p->factor = 2;
+ p->sw_code = mulaw_to_slinear16;
+ } else
+ p->sw_code = ulinear8_to_mulaw;
+ break;
+ case AUDIO_ENCODING_ALAW:
+ if (mode == AUMODE_PLAY) {
+ p->factor = 2;
+ p->sw_code = alaw_to_slinear16;
+ } else
+ p->sw_code = ulinear8_to_alaw;
+ break;
+ default:
+ return (EINVAL);
+ }
+ }
+
+ /* Set the speed */
DPRINTFN(2, ("eap_set_params: old ICSC = 0x%08x\n",
EREAD4(sc, EAP_ICSC)));
div = EREAD4(sc, EAP_ICSC) & ~EAP_PCLKBITS;
- div |= EAP_SET_PCLKDIV(EAP_XTAL_FREQ / p->sample_rate - 2);
+ /*
+ * 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);
+ EWRITE4(sc, EAP_ICSC, div);
DPRINTFN(2, ("eap_set_params: set ICSC = 0x%08x\n", div));
- return (0);
+ return (0);
}
int
@@ -759,169 +777,174 @@ eap_round_blocksize(addr, blk)
}
int
-eap_dma_init_input(addr, buf, cc)
+eap_trigger_output(addr, start, end, blksize, intr, arg, param)
void *addr;
- void *buf;
- int cc;
+ void *start, *end;
+ int blksize;
+ void (*intr) __P((void *));
+ void *arg;
+ struct audio_params *param;
{
struct eap_softc *sc = addr;
struct eap_dma *p;
+ u_int32_t mode;
+ int sampshift;
- DPRINTF(("eap_dma_init_input: dma start loop input addr=%p cc=%d\n",
- buf, cc));
- for (p = sc->sc_dmas; p && KERNADDR(p) != buf; p = p->next)
- ;
- if (!p) {
- printf("eap_dma_init_input: bad addr %p\n", buf);
- return (EINVAL);
- }
- EWRITE4(sc, EAP_MEMPAGE, EAP_ADC_PAGE);
- EWRITE4(sc, EAP_ADC_ADDR, DMAADDR(p));
- EWRITE4(sc, EAP_ADC_SIZE, EAP_SET_SIZE(0, cc / 4 - 1));
- DPRINTF(("eap_dma_init_input: ADC_ADDR=0x%x, ADC_SIZE=0x%x\n",
- (int)DMAADDR(p), EAP_SET_SIZE(0, cc / 4 - 1)));
- return (0);
-}
+#ifdef DIAGNOSTIC
+ if (sc->sc_prun)
+ panic("eap_trigger_output: already running");
+ sc->sc_prun = 1;
+#endif
-int
-eap_dma_init_output(addr, buf, cc)
- void *addr;
- void *buf;
- int cc;
-{
- struct eap_softc *sc = addr;
- struct eap_dma *p;
+ 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);
+ sampshift = 0;
+ if (param->precision * param->factor == 16) {
+ mode |= EAP_P2_S_EB;
+ sampshift++;
+ }
+ if (param->channels == 2) {
+ mode |= EAP_P2_S_MB;
+ sampshift++;
+ }
+ EWRITE4(sc, EAP_SIC, mode);
- DPRINTF(("eap: dma start loop output buf=%p cc=%d\n", buf, cc));
- for (p = sc->sc_dmas; p && KERNADDR(p) != buf; p = p->next)
+ for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
;
if (!p) {
- printf("eap_dma_init_output: bad addr %p\n", buf);
+ printf("eap_trigger_output: bad addr %p\n", start);
return (EINVAL);
}
+
+ DPRINTF(("eap_trigger_output: DAC2_ADDR=0x%x, DAC2_SIZE=0x%x\n",
+ (int)DMAADDR(p), EAP_SET_SIZE(0, ((end - 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, cc / 4 - 1));
- DPRINTF(("eap_dma_init_output: DAC2_ADDR=0x%x, DAC2_SIZE=0x%x\n",
- (int)DMAADDR(p), EAP_SET_SIZE(0, cc / 4 - 1)));
+ EWRITE4(sc, EAP_DAC2_SIZE, EAP_SET_SIZE(0, ((end - 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));
+
return (0);
}
int
-eap_dma_output(addr, p, cc, intr, arg)
+eap_trigger_input(addr, start, end, blksize, intr, arg, param)
void *addr;
- void *p;
- int cc;
+ void *start, *end;
+ int blksize;
void (*intr) __P((void *));
void *arg;
+ struct audio_params *param;
{
struct eap_softc *sc = addr;
+ struct eap_dma *p;
u_int32_t mode;
+ int sampshift;
- DPRINTFN(sc->sc_prun ? 5 : 1,
- ("eap_dma_output: sc=%p buf=%p cc=%d intr=%p(%p)\n",
- addr, p, cc, intr, arg));
- sc->sc_pintr = intr;
- sc->sc_parg = arg;
- if (!sc->sc_prun) {
-#if defined(DIAGNOSTIC) || defined(AUDIO_DEBUG)
- if (sc->sc_sampsize == 0) {
- printf("eap_dma_output: sampsize == 0\n");
- return EINVAL;
- }
+#ifdef DIAGNOSTIC
+ if (sc->sc_rrun)
+ panic("eap_trigger_input: already running");
+ sc->sc_rrun = 1;
#endif
- EWRITE2(sc, EAP_DAC2_CSR, cc / sc->sc_sampsize - 1);
- DPRINTFN(1, ("eap_dma_output: set DAC2_CSR = %d\n",
- cc / sc->sc_sampsize - 1));
- DPRINTFN(1, ("eap_dma_output: old ICSC = 0x%08x\n",
- EREAD4(sc, EAP_ICSC)));
- 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_dma_output: set ICSC = 0x%08x\n", mode));
- sc->sc_prun = 1;
- }
- return (0);
-}
-
-int
-eap_dma_input(addr, p, cc, intr, arg)
- void *addr;
- void *p;
- int cc;
- void (*intr) __P((void *));
- void *arg;
-{
- struct eap_softc *sc = addr;
- u_int32_t mode;
- DPRINTFN(1, ("eap_dma_input: sc=%p buf=%p cc=%d intr=%p(%p)\n",
- addr, p, cc, intr, arg));
+ DPRINTFN(1, ("eap_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
+ addr, start, end, blksize, intr, arg));
sc->sc_rintr = intr;
sc->sc_rarg = arg;
- if (!sc->sc_rrun) {
-#if defined(DIAGNOSTIC) || defined(AUDIO_DEBUG)
- if (sc->sc_sampsize == 0) {
- printf("eap_dma_input: sampsize == 0\n");
- return EINVAL;
- }
-#endif
- EWRITE2(sc, EAP_ADC_CSR, cc / sc->sc_sampsize - 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_dma_input: set ICSC = 0x%08x\n", mode));
- sc->sc_rrun = 1;
+
+ mode = EREAD4(sc, EAP_SIC) & ~(EAP_R1_S_EB | EAP_R1_S_MB);
+ sampshift = 0;
+ if (param->precision * param->factor == 16) {
+ mode |= EAP_R1_S_EB;
+ sampshift++;
+ }
+ if (param->channels == 2) {
+ mode |= EAP_R1_S_MB;
+ sampshift++;
}
- return (0);
+ EWRITE4(sc, EAP_SIC, mode);
+
+ for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
+ ;
+ if (!p) {
+ printf("eap_trigger_input: bad addr %p\n", start);
+ return (EINVAL);
+ }
+
+ DPRINTF(("eap_trigger_input: ADC_ADDR=0x%x, ADC_SIZE=0x%x\n",
+ (int)DMAADDR(p), EAP_SET_SIZE(0, ((end - 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));
+
+ 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));
+
+ return (0);
}
int
-eap_halt_out_dma(addr)
+eap_halt_output(addr)
void *addr;
{
struct eap_softc *sc = addr;
u_int32_t mode;
- DPRINTF(("eap: eap_halt_out_dma\n"));
+ DPRINTF(("eap: eap_halt_output\n"));
mode = EREAD4(sc, EAP_ICSC) & ~EAP_DAC2_EN;
EWRITE4(sc, EAP_ICSC, mode);
+#ifdef DIAGNOSTIC
sc->sc_prun = 0;
- return (0);
+#endif
+ return (0);
}
int
-eap_halt_in_dma(addr)
+eap_halt_input(addr)
void *addr;
{
struct eap_softc *sc = addr;
u_int32_t mode;
- DPRINTF(("eap: eap_halt_in_dma\n"));
+ DPRINTF(("eap: eap_halt_input\n"));
mode = EREAD4(sc, EAP_ICSC) & ~EAP_ADC_EN;
EWRITE4(sc, EAP_ICSC, mode);
+#ifdef DIAGNOSTIC
sc->sc_rrun = 0;
- return (0);
+#endif
+ return (0);
}
int
eap_getdev(addr, retp)
void *addr;
- struct audio_device *retp;
+ struct audio_device *retp;
{
*retp = eap_device;
- return (0);
+ return (0);
}
void
eap_set_mixer(sc, a, d)
struct eap_softc *sc;
- int a, d;
+ int a, d;
{
eap_write_codec(sc, a, d);
- DPRINTFN(1, ("eap_mixer_set_port port 0x%02x = 0x%02x\n", a, d));
+ DPRINTFN(1, ("eap_mixer_set_port port 0x%02x = 0x%02x\n", a, d));
}
@@ -932,7 +955,7 @@ eap_mixer_set_port(addr, cp)
{
struct eap_softc *sc = addr;
int lval, rval, l, r, la, ra;
- int l1, r1, l2, r2, m;
+ int l1, r1, l2, r2, m, o1, o2;
if (cp->dev == EAP_RECORD_SOURCE) {
if (cp->type != AUDIO_MIXER_SET)
@@ -940,7 +963,7 @@ eap_mixer_set_port(addr, cp)
m = sc->sc_record_source = cp->un.mask;
l1 = l2 = r1 = r2 = 0;
if (m & (1 << EAP_VOICE_VOL))
- l2 |= AK_M_VOICE_L, r2 |= AK_M_VOICE_R;
+ l2 |= AK_M_VOICE, r2 |= AK_M_VOICE;
if (m & (1 << EAP_FM_VOL))
l1 |= AK_M_FM_L, r1 |= AK_M_FM_R;
if (m & (1 << EAP_CD_VOL))
@@ -948,7 +971,7 @@ eap_mixer_set_port(addr, cp)
if (m & (1 << EAP_LINE_VOL))
l1 |= AK_M_LINE_L, r1 |= AK_M_LINE_R;
if (m & (1 << EAP_AUX_VOL))
- l2 |= AK_M_AUX_L, r2 |= AK_M_AUX_R;
+ l2 |= AK_M2_AUX_L, r2 |= AK_M2_AUX_R;
if (m & (1 << EAP_MIC_VOL))
l2 |= AK_M_TMIC, r2 |= AK_M_TMIC;
eap_set_mixer(sc, AK_IN_MIXER1_L, l1);
@@ -957,6 +980,36 @@ eap_mixer_set_port(addr, cp)
eap_set_mixer(sc, AK_IN_MIXER2_R, r2);
return (0);
}
+ if (cp->dev == EAP_OUTPUT_SELECT) {
+ if (cp->type != AUDIO_MIXER_SET)
+ return (EINVAL);
+ m = sc->sc_output_source = cp->un.mask;
+ o1 = o2 = 0;
+ if (m & (1 << EAP_VOICE_VOL))
+ o2 |= AK_M_VOICE_L | AK_M_VOICE_R;
+ if (m & (1 << EAP_FM_VOL))
+ o1 |= AK_M_FM_L | AK_M_FM_R;
+ if (m & (1 << EAP_CD_VOL))
+ o1 |= AK_M_CD_L | AK_M_CD_R;
+ if (m & (1 << EAP_LINE_VOL))
+ o1 |= AK_M_LINE_L | AK_M_LINE_R;
+ if (m & (1 << EAP_AUX_VOL))
+ o2 |= AK_M_AUX_L | AK_M_AUX_R;
+ if (m & (1 << EAP_MIC_VOL))
+ o1 |= AK_M_MIC;
+ eap_set_mixer(sc, AK_OUT_MIXER1, o1);
+ eap_set_mixer(sc, AK_OUT_MIXER2, o2);
+ return (0);
+ }
+ if (cp->dev == EAP_MIC_PREAMP) {
+ if (cp->type != AUDIO_MIXER_ENUM)
+ return (EINVAL);
+ if (cp->un.ord != 0 && cp->un.ord != 1)
+ return (EINVAL);
+ sc->sc_mic_preamp = cp->un.ord;
+ eap_set_mixer(sc, AK_MGAIN, cp->un.ord);
+ return (0);
+ }
if (cp->type != AUDIO_MIXER_VALUE)
return (EINVAL);
if (cp->un.value.num_channels == 1)
@@ -1024,8 +1077,20 @@ eap_mixer_get_port(addr, cp)
switch (cp->dev) {
case EAP_RECORD_SOURCE:
+ if (cp->type != AUDIO_MIXER_SET)
+ return (EINVAL);
cp->un.mask = sc->sc_record_source;
return (0);
+ case EAP_OUTPUT_SELECT:
+ if (cp->type != AUDIO_MIXER_SET)
+ return (EINVAL);
+ cp->un.mask = sc->sc_output_source;
+ return (0);
+ case EAP_MIC_PREAMP:
+ if (cp->type != AUDIO_MIXER_ENUM)
+ return (EINVAL);
+ cp->un.ord = sc->sc_mic_preamp;
+ return (0);
case EAP_MASTER_VOL:
l = ATT5_TO_VOL(sc->sc_port[AK_MASTER_L]);
r = ATT5_TO_VOL(sc->sc_port[AK_MASTER_R]);
@@ -1066,7 +1131,8 @@ eap_mixer_get_port(addr, cp)
else if (cp->un.value.num_channels == 2) {
cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
- }
+ } else
+ return (EINVAL);
return (0);
}
@@ -1133,7 +1199,7 @@ eap_query_devinfo(addr, dip)
dip->type = AUDIO_MIXER_VALUE;
dip->mixer_class = EAP_INPUT_CLASS;
dip->prev = AUDIO_MIXER_LAST;
- dip->next = AUDIO_MIXER_LAST;
+ dip->next = EAP_MIC_PREAMP;
strcpy(dip->label.name, AudioNmicrophone);
dip->un.v.num_channels = 1;
strcpy(dip->un.v.units.name, AudioNvolume);
@@ -1143,7 +1209,7 @@ eap_query_devinfo(addr, dip)
dip->prev = dip->next = AUDIO_MIXER_LAST;
strcpy(dip->label.name, AudioNsource);
dip->type = AUDIO_MIXER_SET;
- dip->un.s.num_mem = 5;
+ dip->un.s.num_mem = 6;
strcpy(dip->un.s.member[0].label.name, AudioNmicrophone);
dip->un.s.member[0].mask = 1 << EAP_MIC_VOL;
strcpy(dip->un.s.member[1].label.name, AudioNcd);
@@ -1154,6 +1220,39 @@ eap_query_devinfo(addr, dip)
dip->un.s.member[3].mask = 1 << EAP_FM_VOL;
strcpy(dip->un.s.member[4].label.name, AudioNaux);
dip->un.s.member[4].mask = 1 << EAP_AUX_VOL;
+ strcpy(dip->un.s.member[5].label.name, AudioNdac);
+ dip->un.s.member[5].mask = 1 << EAP_VOICE_VOL;
+ return (0);
+ case EAP_OUTPUT_SELECT:
+ dip->mixer_class = EAP_OUTPUT_CLASS;
+ dip->prev = dip->next = AUDIO_MIXER_LAST;
+ strcpy(dip->label.name, AudioNselect);
+ dip->type = AUDIO_MIXER_SET;
+ dip->un.s.num_mem = 6;
+ strcpy(dip->un.s.member[0].label.name, AudioNmicrophone);
+ dip->un.s.member[0].mask = 1 << EAP_MIC_VOL;
+ strcpy(dip->un.s.member[1].label.name, AudioNcd);
+ dip->un.s.member[1].mask = 1 << EAP_CD_VOL;
+ strcpy(dip->un.s.member[2].label.name, AudioNline);
+ dip->un.s.member[2].mask = 1 << EAP_LINE_VOL;
+ strcpy(dip->un.s.member[3].label.name, AudioNfmsynth);
+ dip->un.s.member[3].mask = 1 << EAP_FM_VOL;
+ strcpy(dip->un.s.member[4].label.name, AudioNaux);
+ dip->un.s.member[4].mask = 1 << EAP_AUX_VOL;
+ strcpy(dip->un.s.member[5].label.name, AudioNdac);
+ dip->un.s.member[5].mask = 1 << EAP_VOICE_VOL;
+ return (0);
+ case EAP_MIC_PREAMP:
+ dip->type = AUDIO_MIXER_ENUM;
+ dip->mixer_class = EAP_INPUT_CLASS;
+ dip->prev = EAP_MIC_VOL;
+ dip->next = AUDIO_MIXER_LAST;
+ strcpy(dip->label.name, AudioNpreamp);
+ dip->un.e.num_mem = 2;
+ strcpy(dip->un.e.member[0].label.name, AudioNoff);
+ dip->un.e.member[0].ord = 0;
+ strcpy(dip->un.e.member[1].label.name, AudioNon);
+ dip->un.e.member[1].ord = 1;
return (0);
case EAP_OUTPUT_CLASS:
dip->type = AUDIO_MIXER_CLASS;
@@ -1185,19 +1284,19 @@ eap_malloc(addr, size, pool, flags)
int flags;
{
struct eap_softc *sc = addr;
- struct eap_dma *p;
- int error;
-
- p = malloc(sizeof(*p), pool, flags);
- if (!p)
- return (0);
- error = eap_allocmem(sc, size, 16, p);
- if (error) {
- free(p, pool);
- return (0);
- }
- p->next = sc->sc_dmas;
- sc->sc_dmas = p;
+ struct eap_dma *p;
+ int error;
+
+ p = malloc(sizeof(*p), pool, flags);
+ if (!p)
+ return (0);
+ error = eap_allocmem(sc, size, 16, p);
+ if (error) {
+ free(p, pool);
+ return (0);
+ }
+ p->next = sc->sc_dmas;
+ sc->sc_dmas = p;
return (KERNADDR(p));
}
@@ -1208,16 +1307,16 @@ eap_free(addr, ptr, pool)
int pool;
{
struct eap_softc *sc = addr;
- struct eap_dma **p;
-
- for (p = &sc->sc_dmas; *p; p = &(*p)->next) {
- if (KERNADDR(*p) == ptr) {
- eap_freemem(sc, *p);
- *p = (*p)->next;
- free(*p, pool);
- return;
- }
- }
+ struct eap_dma **p;
+
+ for (p = &sc->sc_dmas; *p; p = &(*p)->next) {
+ if (KERNADDR(*p) == ptr) {
+ eap_freemem(sc, *p);
+ *p = (*p)->next;
+ free(*p, pool);
+ return;
+ }
+ }
}
u_long
@@ -1231,14 +1330,14 @@ eap_round(addr, size)
int
eap_mappage(addr, mem, off, prot)
void *addr;
- void *mem;
- int off;
+ void *mem;
+ int off;
int prot;
{
struct eap_softc *sc = addr;
- struct eap_dma *p;
+ struct eap_dma *p;
- for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next)
+ for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next)
;
if (!p)
return (-1);
@@ -1250,5 +1349,5 @@ int
eap_get_props(addr)
void *addr;
{
- return (AUDIO_PROP_MMAP | AUDIO_PROP_FULLDUPLEX);
+ return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX);
}