Several things:

* Use the new trigger_{in,out}put interface.
* Allow the play and record channels to have different encodings (but the
  same sample rate).
* Play u-law and a-law as 16-bit data.  (This may not work yet...)
This commit is contained in:
mycroft 1998-08-09 20:32:34 +00:00
parent 17431823fb
commit 4ffebebb25

View File

@ -1,13 +1,13 @@
/* $NetBSD: eap.c,v 1.8 1998/07/06 11:12:21 augustss Exp $ */
/* $NetBSD: eap.c,v 1.9 1998/08/09 20:32:34 mycroft Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Lennart Augustsson <augustss@cs.chalmers.se>
* Charles 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>
*
@ -118,7 +118,6 @@
#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
@ -260,13 +259,15 @@ struct eap_softc {
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 */
@ -290,12 +291,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 *));
@ -316,12 +317,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,
@ -333,6 +334,8 @@ struct audio_hw_if eap_hw_if = {
eap_round,
eap_mappage,
eap_get_props,
eap_trigger_output,
eap_trigger_input,
};
struct audio_device eap_device = {
@ -475,7 +478,7 @@ eap_intr(p)
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 */
nw = ((s & 0xffff) + 1) >> 2; /* # of words in DMA */
n = 0;
while (((EREAD4(sc, EAP_ADC_SIZE) >> 16) + 8) % nw == 0) {
delay(10);
@ -557,12 +560,6 @@ 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);
}
@ -576,8 +573,8 @@ 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;
@ -643,76 +640,92 @@ 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));
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) {
if ((usemode | setmode) == AUMODE_PLAY)
rec->sample_rate = play->sample_rate;
else if ((usemode | setmode) == AUMODE_RECORD)
play->sample_rate = rec->sample_rate;
else
return (EINVAL);
}
pswcode = rswcode = 0;
for (mode = AUMODE_RECORD; mode != -1;
mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
if ((setmode & mode) == 0)
continue;
p = mode == AUMODE_PLAY ? play : rec;
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)
rswcode = pswcode = swap_bytes;
p->sw_code = swap_bytes;
else
pswcode = rswcode = change_sign8;
p->sw_code = change_sign8;
break;
case AUDIO_ENCODING_SLINEAR_LE:
if (p->precision != 16)
pswcode = rswcode = change_sign8;
p->sw_code = change_sign8;
break;
case AUDIO_ENCODING_ULINEAR_BE:
if (p->precision == 16) {
pswcode = swap_bytes_change_sign16;
rswcode = change_sign16_swap_bytes;
}
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)
pswcode = rswcode = change_sign16;
p->sw_code = change_sign16;
break;
case AUDIO_ENCODING_ULAW:
pswcode = mulaw_to_ulinear8;
rswcode = ulinear8_to_mulaw;
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:
pswcode = alaw_to_ulinear8;
rswcode = ulinear8_to_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);
}
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);
sc->sc_sampsize = p->precision / 8 * p->channels; /* bytes / sample */
p->sw_code = pswcode;
r->sw_code = rswcode;
/* 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));
}
/* 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
*/
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));
@ -729,150 +742,161 @@ 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;
{
struct eap_softc *sc = addr;
struct eap_dma *p;
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);
}
int
eap_dma_init_output(addr, buf, cc)
void *addr;
void *buf;
int cc;
{
struct eap_softc *sc = addr;
struct eap_dma *p;
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)
;
if (!p) {
printf("eap_dma_init_output: bad addr %p\n", buf);
return (EINVAL);
}
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)));
return (0);
}
int
eap_dma_output(addr, p, cc, intr, arg)
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));
#ifdef DIAGNOSTIC
if (sc->sc_prun)
panic("eap_trigger_output: already running");
#endif
DPRINTFN(1, ("eap_trigger_output: sc=%p start=%p end=%d blksize=%d intr=%p(%p)\n",
addr, start, end, blksize, 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;
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++;
}
#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)));
if (param->channels == 2) {
mode |= EAP_P2_S_MB;
sampshift++;
}
EWRITE4(sc, EAP_SIC, mode);
for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
;
if (!p) {
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, ((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_dma_output: set ICSC = 0x%08x\n", mode));
DPRINTFN(1, ("eap_trigger_output: set ICSC = 0x%08x\n", mode));
#ifdef DIAGNOSTIC
sc->sc_prun = 1;
}
#endif
return (0);
}
int
eap_dma_input(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(1, ("eap_dma_input: sc=%p buf=%p cc=%d intr=%p(%p)\n",
addr, p, cc, intr, arg));
#ifdef DIAGNOSTIC
if (sc->sc_rrun)
panic("eap_trigger_input: already running");
#endif
DPRINTFN(1, ("eap_trigger_input: sc=%p start=%p end=%d 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;
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++;
}
#endif
EWRITE2(sc, EAP_ADC_CSR, cc / sc->sc_sampsize - 1);
if (param->channels == 2) {
mode |= EAP_R1_S_MB;
sampshift++;
}
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_dma_input: set ICSC = 0x%08x\n", mode));
DPRINTFN(1, ("eap_trigger_input: set ICSC = 0x%08x\n", mode));
#ifdef DIAGNOSTIC
sc->sc_rrun = 1;
}
#endif
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;
#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;
#endif
return (0);
}
@ -1265,5 +1289,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);
}