* Snap the sample rate when setting it, and remember only the time constant.
* Set the time constant when changing between play/record.
* Always return the actual sample rate with AUDIO_GETINFO.
This commit is contained in:
mycroft 1996-02-16 10:10:21 +00:00
parent 19f59bf3c2
commit 7847c9efee
2 changed files with 207 additions and 253 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: sbdsp.c,v 1.15 1996/02/16 08:07:40 mycroft Exp $ */
/* $NetBSD: sbdsp.c,v 1.16 1996/02/16 10:10:21 mycroft Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@ -81,20 +81,54 @@ struct {
int wmidi;
} sberr;
/*
* Time constant routines follow. See SBK, section 12.
* Although they don't come out and say it (in the docs),
* the card clearly uses a 1MHz countdown timer, as the
* low-speed formula (p. 12-4) is:
* tc = 256 - 10^6 / sr
* In high-speed mode, the constant is the upper byte of a 16-bit counter,
* and a 256MHz clock is used:
* tc = 65536 - 256 * 10^ 6 / sr
* Since we can only use the upper byte of the HS TC, the two formulae
* are equivalent. (Why didn't they say so?) E.g.,
* (65536 - 256 * 10 ^ 6 / x) >> 8 = 256 - 10^6 / x
*
* The crossover point (from low- to high-speed modes) is different
* for the SBPRO and SB20. The table on p. 12-5 gives the following data:
*
* SBPRO SB20
* ----- --------
* input ls min 4 KHz 4 KHz
* input ls max 23 KHz 13 KHz
* input hs max 44.1 KHz 15 KHz
* output ls min 4 KHz 4 KHz
* output ls max 23 KHz 23 KHz
* output hs max 44.1 KHz 44.1 KHz
*/
#define SB_LS_MIN 0x06 /* 4000 Hz */
#define SB_8K 0x83 /* 8000 Hz */
#define SBPRO_ADC_LS_MAX 0xd4 /* 22727 Hz */
#define SBPRO_ADC_HS_MAX 0xea /* 45454 Hz */
#define SBCLA_ADC_LS_MAX 0xb3 /* 12987 Hz */
#define SBCLA_ADC_HS_MAX 0xbd /* 14925 Hz */
#define SB_DAC_LS_MAX 0xd4 /* 22727 Hz */
#define SB_DAC_HS_MAX 0xea /* 45454 Hz */
#ifdef AUDIO_DEBUG
void
sb_printsc(struct sbdsp_softc *sc)
{
int i;
printf("open %d dmachan %d iobase %x\n", sc->sc_open, sc->sc_drq,
sc->sc_iobase);
printf("hispeed %d irate %d orate %d encoding %x\n",
sc->sc_adacmode, sc->sc_irate, sc->sc_orate, sc->encoding);
printf("open %d dmachan %d iobase %x\n",
sc->sc_open, sc->sc_drq, sc->sc_iobase);
printf("itc %d imode %d otc %d omode %d encoding %x\n",
sc->sc_itc, sc->sc_imode, sc->sc_otc, sc->sc_omode, sc->encoding);
printf("outport %d inport %d spkron %d nintr %d\n",
sc->out_port, sc->in_port, sc->spkr_state, sc->sc_interrupts);
printf("tc %x chans %x scintr %x arg %x\n", sc->sc_adactc, sc->sc_chans,
sc->sc_intr, sc->sc_arg);
printf("chans %x intr %x arg %x\n",
sc->sc_chans, sc->sc_intr, sc->sc_arg);
printf("gain: ");
for (i = 0; i < SB_NDEVS; i++)
printf("%d ", sc->gain[i]);
@ -136,15 +170,12 @@ sbdsp_attach(sc)
/* Set defaults */
if (ISSBPROCLASS(sc))
sc->sc_irate = sc->sc_orate = 45454;
sc->sc_itc = sc->sc_otc = SBPRO_ADC_HS_MAX;
else
sc->sc_irate = sc->sc_orate = 14925;
sc->sc_itc = sc->sc_otc = SBCLA_ADC_HS_MAX;
sc->sc_chans = 1;
sc->encoding = AUDIO_ENCODING_LINEAR;
(void) sbdsp_set_in_sr_real(sc, sc->sc_irate);
(void) sbdsp_set_out_sr_real(sc, sc->sc_orate);
(void) sbdsp_set_in_port(sc, SB_MIC_PORT);
(void) sbdsp_set_out_port(sc, SB_SPEAKER);
@ -166,6 +197,7 @@ sbdsp_attach(sc)
for (i = 0; i < SB_NDEVS; i++)
sc->gain[i] = sbdsp_stereo_vol(SBP_MAXVOL, SBP_MAXVOL);
}
printf(": dsp v%d.%02d\n",
SBVER_MAJOR(sc->sc_model), SBVER_MINOR(sc->sc_model));
}
@ -205,25 +237,7 @@ sbdsp_set_in_sr(addr, sr)
{
register struct sbdsp_softc *sc = addr;
sc->sc_irate = sr;
return 0;
}
int
sbdsp_set_in_sr_real(addr, sr)
void *addr;
u_long sr;
{
register struct sbdsp_softc *sc = addr;
int rval;
if (rval = sbdsp_set_sr(sc, &sr, SB_INPUT_RATE))
return rval;
sc->sc_irate = sr;
if (sc->sc_dmadir == SBP_DMA_IN)
sc->sc_dmadir = SBP_DMA_NONE; /* do it again on next DMA in */
return 0;
return (sbdsp_srtotc(sc, sr, SB_INPUT_RATE, &sc->sc_itc, &sc->sc_imode));
}
u_long
@ -232,7 +246,7 @@ sbdsp_get_in_sr(addr)
{
register struct sbdsp_softc *sc = addr;
return(sc->sc_irate);
return (sbdsp_tctosr(sc, sc->sc_itc));
}
int
@ -242,24 +256,7 @@ sbdsp_set_out_sr(addr, sr)
{
register struct sbdsp_softc *sc = addr;
sc->sc_orate = sr;
return(0);
}
int
sbdsp_set_out_sr_real(addr, sr)
void *addr;
u_long sr;
{
register struct sbdsp_softc *sc = addr;
int rval;
if (rval = sbdsp_set_sr(sc, &sr, SB_OUTPUT_RATE))
return rval;
sc->sc_orate = sr;
if (sc->sc_dmadir == SBP_DMA_OUT)
sc->sc_dmadir = SBP_DMA_NONE; /* do it again on next DMA out */
return 0;
return (sbdsp_srtotc(sc, sr, SB_OUTPUT_RATE, &sc->sc_otc, &sc->sc_omode));
}
u_long
@ -268,7 +265,7 @@ sbdsp_get_out_sr(addr)
{
register struct sbdsp_softc *sc = addr;
return(sc->sc_orate);
return (sbdsp_tctosr(sc, sc->sc_otc));
}
int
@ -289,7 +286,6 @@ sbdsp_query_encoding(addr, fp)
break;
default:
return (EINVAL);
/*NOTREACHED*/
}
return (0);
}
@ -347,26 +343,27 @@ sbdsp_set_channels(addr, chans)
int chans;
{
register struct sbdsp_softc *sc = addr;
int rval;
if (ISSBPROCLASS(sc)) {
if (chans != 1 && chans != 2)
return (EINVAL);
sc->sc_chans = chans;
#if 0
if (rval = sbdsp_set_in_sr_real(addr, sc->sc_irate))
return rval;
#endif
sbdsp_mix_write(sc, SBP_STEREO,
(sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) |
(chans == 2 ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO));
/* recording channels needs to be done right when we start
DMA recording. Just record number of channels for now
and set stereo when ready. */
}
else {
} else {
if (chans != 1)
return (EINVAL);
sc->sc_chans = 1;
sc->sc_chans = chans;
}
return (0);
@ -381,16 +378,12 @@ sbdsp_get_channels(addr)
#if 0
/* recording stereo may frob the mixer output */
if (ISSBPROCLASS(sc)) {
if ((sbdsp_mix_read(sc, SBP_STEREO) & SBP_PLAYMODE_MASK) == SBP_PLAYMODE_STEREO) {
if ((sbdsp_mix_read(sc, SBP_STEREO) & SBP_PLAYMODE_MASK) == SBP_PLAYMODE_STEREO)
sc->sc_chans = 2;
}
else {
else
sc->sc_chans = 1;
}
}
else {
} else
sc->sc_chans = 1;
}
#endif
return (sc->sc_chans);
@ -444,10 +437,8 @@ sbdsp_set_in_port(addr, port)
case SB_FM_PORT:
default:
return (EINVAL);
/*NOTREACHED*/
}
}
else {
} else {
switch (port) {
case SB_MIC_PORT:
sbport = SBP_FROM_MIC;
@ -455,7 +446,6 @@ sbdsp_set_in_port(addr, port)
break;
default:
return (EINVAL);
/*NOTREACHED*/
}
}
@ -513,11 +503,12 @@ sbdsp_round_blocksize(addr, blk)
sc->sc_last_hs_size = 0;
/* Higher speeds need bigger blocks to avoid popping and silence gaps. */
if ((sc->sc_orate > 8000 || sc->sc_irate > 8000) &&
if ((sc->sc_otc > SB_8K || sc->sc_itc > SB_8K) &&
(blk > NBPG/2 || blk < NBPG/4))
blk = NBPG/2;
/* don't try to DMA too much at once, though. */
if (blk > NBPG) blk = NBPG;
if (blk > NBPG)
blk = NBPG;
if (sc->sc_chans == 2)
return (blk & ~1); /* must be even to preserve stereo separation */
else
@ -528,15 +519,18 @@ int
sbdsp_commit_settings(addr)
void *addr;
{
register struct sbdsp_softc *sc = addr;
/* due to potentially unfortunate ordering in the above layers,
re-do a few sets which may be important--input gains
(adjust the proper channels), number of input channels (hit the
record rate and set mode) */
register struct sbdsp_softc *sc = addr;
sbdsp_set_out_sr_real(addr, sc->sc_orate);
sbdsp_set_in_sr_real(addr, sc->sc_irate);
/*
* XXX
* Should wait for chip to be idle.
*/
sc->sc_dmadir = SB_DMA_NONE;
return 0;
}
@ -604,9 +598,9 @@ sbdsp_reset(sc)
register int iobase = sc->sc_iobase;
sc->sc_intr = 0;
if (sc->sc_dmadir != SBP_DMA_NONE) {
if (sc->sc_dmadir != SB_DMA_NONE) {
isa_dmaabort(sc->sc_drq);
sc->sc_dmadir = SBP_DMA_NONE;
sc->sc_dmadir = SB_DMA_NONE;
}
sc->sc_last_hs_size = 0;
@ -768,39 +762,6 @@ sbdsp_contdma(addr)
return(0);
}
/*
* Time constant routines follow. See SBK, section 12.
* Although they don't come out and say it (in the docs),
* the card clearly uses a 1MHz countdown timer, as the
* low-speed formula (p. 12-4) is:
* tc = 256 - 10^6 / sr
* In high-speed mode, the constant is the upper byte of a 16-bit counter,
* and a 256MHz clock is used:
* tc = 65536 - 256 * 10^ 6 / sr
* Since we can only use the upper byte of the HS TC, the two formulae
* are equivalent. (Why didn't they say so?) E.g.,
* (65536 - 256 * 10 ^ 6 / x) >> 8 = 256 - 10^6 / x
*
* The crossover point (from low- to high-speed modes) is different
* for the SBPRO and SB20. The table on p. 12-5 gives the following data:
*
* SBPRO SB20
* ----- --------
* input ls min 4 KHz 4 KHz
* input ls max 23 KHz 13 KHz
* input hs max 44.1 KHz 15 KHz
* output ls min 4 KHz 4 KHz
* output ls max 23 KHz 23 KHz
* output hs max 44.1 KHz 44.1 KHz
*/
#define SB_LS_MIN 0x06 /* 4000 Hz */
#define SBPRO_ADC_LS_MAX 0xd4 /* 22727 Hz */
#define SBPRO_ADC_HS_MAX 0xea /* 45454 Hz */
#define SBCLA_ADC_LS_MAX 0xb3 /* 12987 Hz */
#define SBCLA_ADC_HS_MAX 0xbd /* 14925 Hz */
#define SB_DAC_LS_MAX 0xd4 /* 22727 Hz */
#define SB_DAC_HS_MAX 0xea /* 45454 Hz */
/*
* Convert a linear sampling rate into the DAC time constant.
* Set *mode to indicate the high/low-speed DMA operation.
@ -810,53 +771,60 @@ sbdsp_contdma(addr)
* so isdac indicates output, and !isdac indicates input.
*/
int
sbdsp_srtotc(sc, sr, mode, isdac)
sbdsp_srtotc(sc, sr, isdac, tcp, modep)
register struct sbdsp_softc *sc;
int sr;
int *mode;
int isdac;
int *tcp, *modep;
{
int adc_ls_max, adc_hs_max;
register int tc;
int tc, mode;
if (sr == 0) {
*mode = SB_ADAC_LS;
return SB_LS_MIN;
tc = SB_LS_MIN;
mode = SB_ADAC_LS;
goto out;
}
tc = 256 - 1000000 / sr;
tc = 256 - (1000000 / sr);
if (tc < SB_LS_MIN) {
tc = SB_LS_MIN;
mode = SB_ADAC_LS;
goto out;
} else if (isdac) {
if (tc <= SB_DAC_LS_MAX)
mode = SB_ADAC_LS;
else {
mode = SB_ADAC_HS;
if (tc > SB_DAC_HS_MAX)
tc = SB_DAC_HS_MAX;
}
} else {
int adc_ls_max, adc_hs_max;
/* XXX use better rounding--compare distance to nearest tc on both
sides of requested speed */
if (ISSBPROCLASS(sc)) {
adc_ls_max = SBPRO_ADC_LS_MAX;
adc_hs_max = SBPRO_ADC_HS_MAX;
}
else {
} else {
adc_ls_max = SBCLA_ADC_LS_MAX;
adc_hs_max = SBCLA_ADC_HS_MAX;
}
if (tc < SB_LS_MIN) {
tc = SB_LS_MIN;
*mode = SB_ADAC_LS;
} else if (isdac) {
if (tc <= SB_DAC_LS_MAX)
*mode = SB_ADAC_LS;
else {
*mode = SB_ADAC_HS;
if (tc > SB_DAC_HS_MAX)
tc = SB_DAC_HS_MAX;
}
} else {
if (tc <= adc_ls_max)
*mode = SB_ADAC_LS;
mode = SB_ADAC_LS;
else {
*mode = SB_ADAC_HS;
mode = SB_ADAC_HS;
if (tc > adc_hs_max)
tc = adc_hs_max;
}
}
return tc;
out:
*tcp = tc;
*modep = mode;
return (0);
}
/*
@ -882,47 +850,27 @@ sbdsp_tctosr(sc, tc)
}
int
sbdsp_set_sr(sc, srp, isdac)
sbdsp_set_tc(sc, tc)
register struct sbdsp_softc *sc;
u_long *srp;
int isdac;
int tc;
{
register int tc;
int mode;
int sr = *srp;
register int iobase;
/*
* A SBPro in stereo mode uses time constants at double the
* actual rate.
*/
if (ISSBPRO(sc) && sc->sc_chans == 2) {
if (sr > 22727)
sr = 22727; /* Can't bounce it...order of
operations may yield bogus
sr here. */
sr *= 2;
}
else if (!ISSBPROCLASS(sc) && sc->sc_chans != 1)
return EINVAL;
if (ISSBPRO(sc) && sc->sc_chans == 2)
tc = 256 - ((256 - tc) / 2);
tc = sbdsp_srtotc(sc, sr, &mode, isdac);
DPRINTF(("sbdsp_set_sr: sc=0x%x sr=%d mode=0x%x\n", sc, sr, mode));
DPRINTF(("sbdsp_set_tc: sc=%p tc=%d\n", sc, tc));
iobase = sc->sc_iobase;
if (sbdsp_wdsp(iobase, SB_DSP_TIMECONST) < 0 ||
sbdsp_wdsp(iobase, tc) < 0)
return EIO;
return (EIO);
sr = sbdsp_tctosr(sc, tc);
if (ISSBPRO(sc) && sc->sc_chans == 2)
*srp = sr / 2;
else
*srp = sr;
sc->sc_adacmode = mode;
sc->sc_adactc = tc;
return 0;
return (0);
}
int
@ -946,22 +894,24 @@ sbdsp_dma_input(addr, p, cc, intr, arg)
}
iobase = sc->sc_iobase;
if (ISSBPROCLASS(sc) && sc->sc_dmadir != SBP_DMA_IN) {
if (sc->sc_dmadir != SB_DMA_IN) {
if (ISSBPROCLASS(sc)) {
if (sc->sc_chans == 2) {
if (sbdsp_wdsp(iobase, SB_DSP_RECORD_STEREO) < 0)
goto badmode;
sbdsp_mix_write(sc, SBP_INFILTER,
sbdsp_mix_read(sc, SBP_INFILTER) | SBP_FILTER_OFF);
}
else {
} else {
if (sbdsp_wdsp(iobase, SB_DSP_RECORD_MONO) < 0)
goto badmode;
sbdsp_mix_write(sc, SBP_INFILTER,
sc->sc_irate <= 8000 ?
sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_FILTER_MASK :
sbdsp_mix_read(sc, SBP_INFILTER) | SBP_FILTER_OFF);
sbdsp_mix_write(sc, SBP_INFILTER, sc->sc_itc > SB_8K ?
sbdsp_mix_read(sc, SBP_INFILTER) | SBP_FILTER_OFF :
sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_FILTER_MASK);
}
sc->sc_dmadir = SBP_DMA_IN;
}
sbdsp_set_tc(sc, sc->sc_itc);
sc->sc_dmadir = SB_DMA_IN;
}
isa_dmastart(B_READ, p, cc, sc->sc_drq);
@ -971,7 +921,7 @@ sbdsp_dma_input(addr, p, cc, intr, arg)
sc->dmaaddr = p;
sc->dmacnt = --cc; /* DMA controller is strange...? */
if (sc->sc_adacmode == SB_ADAC_LS) {
if (sc->sc_imode == SB_ADAC_LS) {
if (sbdsp_wdsp(iobase, SB_DSP_RDMA) < 0 ||
sbdsp_wdsp(iobase, cc) < 0 ||
sbdsp_wdsp(iobase, cc >> 8) < 0) {
@ -1027,14 +977,17 @@ sbdsp_dma_output(addr, p, cc, intr, arg)
}
iobase = sc->sc_iobase;
if (ISSBPROCLASS(sc) && sc->sc_dmadir != SBP_DMA_OUT) {
if (sc->sc_dmadir != SB_DMA_OUT) {
if (ISSBPROCLASS(sc)) {
/* make sure we re-set stereo mixer bit when we start
output. */
sbdsp_mix_write(sc, SBP_STEREO,
(sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) |
(sc->sc_chans == 2 ?
SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO));
sc->sc_dmadir = SBP_DMA_OUT;
(sc->sc_chans == 2 ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO));
}
sbdsp_set_tc(sc, sc->sc_otc);
sc->sc_dmadir = SB_DMA_OUT;
}
isa_dmastart(B_WRITE, p, cc, sc->sc_drq);
@ -1044,7 +997,7 @@ sbdsp_dma_output(addr, p, cc, intr, arg)
sc->dmaaddr = p;
sc->dmacnt = --cc; /* a vagary of how DMA works, apparently. */
if (sc->sc_adacmode == SB_ADAC_LS) {
if (sc->sc_omode == SB_ADAC_LS) {
if (sbdsp_wdsp(iobase, SB_DSP_WDMA) < 0 ||
sbdsp_wdsp(iobase, cc) < 0 ||
sbdsp_wdsp(iobase, cc >> 8) < 0) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: sbdspvar.h,v 1.8 1996/02/16 08:07:46 mycroft Exp $ */
/* $NetBSD: sbdspvar.h,v 1.9 1996/02/16 10:10:23 mycroft Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@ -80,10 +80,6 @@ struct sbdsp_softc {
int sc_drq; /* DMA */
u_short sc_open; /* reference count of open calls */
u_short sc_adacmode; /* low/high speed mode indicator */
u_long sc_irate; /* Sample rate for input */
u_long sc_orate; /* ...and output */
u_int gain[SB_NDEVS]; /* kept in SB levels: right/left each
in a nibble */
@ -95,9 +91,14 @@ struct sbdsp_softc {
u_int spkr_state; /* non-null is on */
int sc_itc; /* Sample rate for input */
int sc_otc; /* ...and output */
int sc_imode;
int sc_omode;
#define SB_ADAC_LS 0
#define SB_ADAC_HS 1
u_short sc_adactc; /* current adac time constant */
u_long sc_interrupts; /* number of interrupts taken */
void (*sc_intr)(void*); /* dma completion intr handler */
void (*sc_mintr)(void*, int);/* midi input intr handler */
@ -109,9 +110,9 @@ struct sbdsp_softc {
int sc_last_hs_size; /* last HS dma size */
int sc_chans; /* # of channels */
int sc_dmadir; /* DMA direction */
#define SBP_DMA_NONE 0
#define SBP_DMA_IN 1
#define SBP_DMA_OUT 2
#define SB_DMA_NONE 0
#define SB_DMA_IN 1
#define SB_DMA_OUT 2
u_int sc_model; /* DSP model */
#define SBVER_MAJOR(v) ((v)>>8)