diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/eap.c | 715 |
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); } |