diff options
author | cg <cg@FreeBSD.org> | 2001-05-30 22:38:31 +0000 |
---|---|---|
committer | cg <cg@FreeBSD.org> | 2001-05-30 22:38:31 +0000 |
commit | 67fa2b23c688f8e0aabf6145e161e466255bf08e (patch) | |
tree | 18e96b1d78ffd9f224acc212a89f7fc17237d4a7 /sys/dev/sound/pci/csapcm.c | |
parent | 2c8f781b182182f0727542e807496bce89be2bc6 (diff) | |
download | FreeBSD-src-67fa2b23c688f8e0aabf6145e161e466255bf08e.zip FreeBSD-src-67fa2b23c688f8e0aabf6145e161e466255bf08e.tar.gz |
update this driver to use new firmware and incorporate many fixes.
this works on cs4630 chips, and should implement the clkrun hack for
thinkpads- this will display diagnostic messages when triggered until its
correctness is established.
Diffstat (limited to 'sys/dev/sound/pci/csapcm.c')
-rw-r--r-- | sys/dev/sound/pci/csapcm.c | 272 |
1 files changed, 104 insertions, 168 deletions
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c index 399ac15..19ea977 100644 --- a/sys/dev/sound/pci/csapcm.c +++ b/sys/dev/sound/pci/csapcm.c @@ -40,6 +40,11 @@ #include <pci/pcireg.h> #include <pci/pcivar.h> +/* Buffer size on dma transfer. Fixed for CS416x. */ +#define CS461x_BUFFSIZE (4 * 1024) + +#define GOF_PER_SEC 200 + /* device private data */ struct csa_info; @@ -48,7 +53,7 @@ struct csa_chinfo { struct pcm_channel *channel; struct snd_dbuf *buffer; int dir; - u_int32_t fmt; + u_int32_t fmt, spd; int dma; }; @@ -57,7 +62,9 @@ struct csa_info { void *ih; /* Interrupt cookie */ bus_dma_tag_t parent_dmat; /* DMA tag */ struct csa_bridgeinfo *binfo; /* The state of the parent. */ + struct csa_card *card; + int active; /* Contents of board's registers */ u_long pfie; u_long pctl; @@ -76,8 +83,6 @@ static void csa_startplaydma(struct csa_info *csa); static void csa_startcapturedma(struct csa_info *csa); static void csa_stopplaydma(struct csa_info *csa); static void csa_stopcapturedma(struct csa_info *csa); -static void csa_powerupadc(csa_res *resp); -static void csa_powerupdac(csa_res *resp); static int csa_startdsp(csa_res *resp); static int csa_allocres(struct csa_info *scp, device_t dev); static void csa_releaseres(struct csa_info *scp, device_t dev); @@ -103,6 +108,24 @@ static u_int32_t csa_recfmt[] = { static struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0}; /* -------------------------------------------------------------------- */ + +static int +csa_active(struct csa_info *csa, int run) +{ + int old, go; + + old = csa->active; + csa->active += run; + + if ((csa->active == 0 && old == 1) || (csa->active == 1 && old == 0)) { + go = csa->active; + if (csa->card->active) + return csa->card->active(go); + } + return 0; +} + +/* -------------------------------------------------------------------- */ /* ac97 codec */ static int @@ -111,8 +134,10 @@ csa_rdcd(kobj_t obj, void *devinfo, int regno) u_int32_t data; struct csa_info *csa = (struct csa_info *)devinfo; + csa_active(csa, 1); if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data)) data = 0; + csa_active(csa, -1); return data; } @@ -122,7 +147,9 @@ csa_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) { struct csa_info *csa = (struct csa_info *)devinfo; + csa_active(csa, 1); csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data); + csa_active(csa, -1); return 0; } @@ -380,86 +407,6 @@ csa_stopcapturedma(struct csa_info *csa) } } -static void -csa_powerupdac(csa_res *resp) -{ - int i; - u_long ul; - - /* - * Power on the DACs on the AC97 codec. We turn off the DAC - * powerdown bit and write the new value of the power control - * register. - */ - ul = csa_readio(resp, BA0_AC97_POWERDOWN); - ul &= 0xfdff; - csa_writeio(resp, BA0_AC97_POWERDOWN, ul); - - /* - * Now, we wait until we sample a DAC ready state. - */ - for (i = 0 ; i < 32 ; i++) { - /* - * First, lets wait a short while to let things settle out a - * bit, and to prevent retrying the read too quickly. - */ - DELAY(125); - - /* - * Read the current state of the power control register. - */ - ul = csa_readio(resp, BA0_AC97_POWERDOWN); - - /* - * If the DAC ready state bit is set, then stop waiting. - */ - if ((ul & 0x2) != 0) - break; - } - /* - * The DACs are now calibrated, so we can unmute the DAC output. - */ - csa_writeio(resp, BA0_AC97_PCM_OUT_VOLUME, 0x0808); -} - -static void -csa_powerupadc(csa_res *resp) -{ - int i; - u_long ul; - - /* - * Power on the ADCs on the AC97 codec. We turn off the ADC - * powerdown bit and write the new value of the power control - * register. - */ - ul = csa_readio(resp, BA0_AC97_POWERDOWN); - ul &= 0xfeff; - csa_writeio(resp, BA0_AC97_POWERDOWN, ul); - - /* - * Now, we wait until we sample a ADC ready state. - */ - for (i = 0 ; i < 32 ; i++) { - /* - * First, lets wait a short while to let things settle out a - * bit, and to prevent retrying the read too quickly. - */ - DELAY(125); - - /* - * Read the current state of the power control register. - */ - ul = csa_readio(resp, BA0_AC97_POWERDOWN); - - /* - * If the ADC ready state bit is set, then stop waiting. - */ - if ((ul & 0x1) != 0) - break; - } -} - static int csa_startdsp(csa_res *resp) { @@ -486,11 +433,7 @@ csa_startdsp(csa_res *resp) /* * Wait a little bit, so we don't issue PCI reads too frequently. */ -#if notdef - DELAY(1000); -#else - DELAY(125); -#endif /* notdef */ + DELAY(50); /* * Fetch the current value of the SP status register. */ @@ -511,6 +454,55 @@ csa_startdsp(csa_res *resp) return (0); } +static int +csa_setupchan(struct csa_chinfo *ch) +{ + struct csa_info *csa = ch->parent; + csa_res *resp = &csa->res; + u_long pdtc, tmp; + + if (ch->dir == PCMDIR_PLAY) { + /* direction */ + csa_writemem(resp, BA1_PBA, vtophys(sndbuf_getbuf(ch->buffer))); + + /* format */ + csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f; + if (!(ch->fmt & AFMT_SIGNED)) + csa->pfie |= 0x8000; + if (ch->fmt & AFMT_BIGENDIAN) + csa->pfie |= 0x4000; + if (!(ch->fmt & AFMT_STEREO)) + csa->pfie |= 0x2000; + if (ch->fmt & AFMT_8BIT) + csa->pfie |= 0x1000; + csa_writemem(resp, BA1_PFIE, csa->pfie); + + tmp = 4; + if (ch->fmt & AFMT_16BIT) + tmp <<= 1; + if (ch->fmt & AFMT_STEREO) + tmp <<= 1; + tmp--; + + pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000001ff; + pdtc |= tmp; + csa_writemem(resp, BA1_PDTC, pdtc); + + /* rate */ + csa_setplaysamplerate(resp, ch->spd); + } else if (ch->dir == PCMDIR_REC) { + /* direction */ + csa_writemem(resp, BA1_CBA, vtophys(sndbuf_getbuf(ch->buffer))); + + /* format */ + csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); + + /* rate */ + csa_setcapturesamplerate(resp, ch->spd); + } + return 0; +} + /* -------------------------------------------------------------------- */ /* channel interface */ @@ -523,59 +515,16 @@ csachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel * ch->parent = csa; ch->channel = c; ch->buffer = b; + ch->dir = dir; if (sndbuf_alloc(ch->buffer, csa->parent_dmat, CS461x_BUFFSIZE) == -1) return NULL; return ch; } static int -csachan_setdir(kobj_t obj, void *data, int dir) -{ - struct csa_chinfo *ch = data; - struct csa_info *csa = ch->parent; - csa_res *resp; - - resp = &csa->res; - - if (dir == PCMDIR_PLAY) - csa_writemem(resp, BA1_PBA, vtophys(sndbuf_getbuf(ch->buffer))); - else - csa_writemem(resp, BA1_CBA, vtophys(sndbuf_getbuf(ch->buffer))); - ch->dir = dir; - return 0; -} - -static int csachan_setformat(kobj_t obj, void *data, u_int32_t format) { struct csa_chinfo *ch = data; - struct csa_info *csa = ch->parent; - u_long pdtc; - csa_res *resp; - - resp = &csa->res; - if (ch->dir == PCMDIR_REC) - csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); - else { - csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f; - if (format & AFMT_U8 || format & AFMT_U16_LE || format & AFMT_U16_BE) - csa->pfie |= 0x8000; - if (format & AFMT_S16_BE || format & AFMT_U16_BE) - csa->pfie |= 0x4000; - if (!(format & AFMT_STEREO)) - csa->pfie |= 0x2000; - if (format & AFMT_U8 || format & AFMT_S8) - csa->pfie |= 0x1000; - csa_writemem(resp, BA1_PFIE, csa->pfie); - pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000003ff; - if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) && (format & AFMT_STEREO)) - pdtc |= 0x00f; - else if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) || (format & AFMT_STEREO)) - pdtc |= 0x007; - else - pdtc |= 0x003; - csa_writemem(resp, BA1_PDTC, pdtc); - } ch->fmt = format; return 0; } @@ -584,22 +533,9 @@ static int csachan_setspeed(kobj_t obj, void *data, u_int32_t speed) { struct csa_chinfo *ch = data; - struct csa_info *csa = ch->parent; - csa_res *resp; - - resp = &csa->res; - if (ch->dir == PCMDIR_PLAY) - csa_setplaysamplerate(resp, speed); - else if (ch->dir == PCMDIR_REC) - csa_setcapturesamplerate(resp, speed); - - /* rec/play speeds locked together - should indicate in flags */ -#if 0 - if (ch->direction == PCMDIR_PLAY) d->rec[0].speed = speed; - else d->play[0].speed = speed; -#endif - return speed; /* XXX calc real speed */ + ch->spd = speed; + return ch->spd; /* XXX calc real speed */ } static int @@ -617,16 +553,19 @@ csachan_trigger(kobj_t obj, void *data, int go) if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0; - if (ch->dir == PCMDIR_PLAY) { - if (go == PCMTRIG_START) + if (go == PCMTRIG_START) { + csa_active(csa, 1); + csa_setupchan(ch); + if (ch->dir == PCMDIR_PLAY) csa_startplaydma(csa); else - csa_stopplaydma(csa); - } else { - if (go == PCMTRIG_START) csa_startcapturedma(csa); + } else { + if (ch->dir == PCMDIR_PLAY) + csa_stopplaydma(csa); else csa_stopcapturedma(csa); + csa_active(csa, -1); } return 0; } @@ -663,7 +602,6 @@ csachan_getcaps(kobj_t obj, void *data) static kobj_method_t csachan_methods[] = { KOBJMETHOD(channel_init, csachan_init), - KOBJMETHOD(channel_setdir, csachan_setdir), KOBJMETHOD(channel_setformat, csachan_setformat), KOBJMETHOD(channel_setspeed, csachan_setspeed), KOBJMETHOD(channel_setblocksize, csachan_setblocksize), @@ -677,7 +615,7 @@ CHANNEL_DECLARE(csachan); /* -------------------------------------------------------------------- */ /* The interrupt handler */ static void -csa_intr (void *p) +csa_intr(void *p) { struct csa_info *csa = p; @@ -704,16 +642,13 @@ csa_init(struct csa_info *csa) csa_stopplaydma(csa); csa_stopcapturedma(csa); - /* Crank up the power on the DAC and ADC. */ - csa_powerupadc(resp); - csa_powerupdac(resp); + if (csa_startdsp(resp)) + return (1); + /* Crank up the power on the DAC and ADC. */ csa_setplaysamplerate(resp, 8000); csa_setcapturesamplerate(resp, 8000); - if (csa_startdsp(resp)) - return (1); - return 0; } @@ -725,12 +660,12 @@ csa_allocres(struct csa_info *csa, device_t dev) resp = &csa->res; if (resp->io == NULL) { - resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, CS461x_IO_SIZE, RF_ACTIVE); + resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, 1, RF_ACTIVE); if (resp->io == NULL) return (1); } if (resp->mem == NULL) { - resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, CS461x_MEM_SIZE, RF_ACTIVE); + resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, 1, RF_ACTIVE); if (resp->mem == NULL) return (1); } @@ -781,9 +716,6 @@ csa_releaseres(struct csa_info *csa, device_t dev) } } -static int pcmcsa_probe(device_t dev); -static int pcmcsa_attach(device_t dev); - static int pcmcsa_probe(device_t dev) { @@ -825,17 +757,20 @@ pcmcsa_attach(device_t dev) * respectively. */ csa->pch.dma = csa->rch.dma = 1; + csa->active = 0; + csa->card = csa->binfo->card; /* Allocate the resources. */ resp = &csa->res; - resp->io_rid = CS461x_IO_OFFSET; - resp->mem_rid = CS461x_MEM_OFFSET; + resp->io_rid = PCIR_MAPS; + resp->mem_rid = PCIR_MAPS + 4; resp->irq_rid = 0; if (csa_allocres(csa, dev)) { csa_releaseres(csa, dev); return (ENXIO); } + csa_active(csa, 1); if (csa_init(csa)) { csa_releaseres(csa, dev); return (ENXIO); @@ -854,13 +789,14 @@ pcmcsa_attach(device_t dev) snprintf(status, SND_STATUSLEN, "at irq %ld", rman_get_start(resp->irq)); /* Enable interrupt. */ - if (snd_setup_intr(dev, resp->irq, 0, csa_intr, csa, &csa->ih)) { + if (snd_setup_intr(dev, resp->irq, INTR_MPSAFE, csa_intr, csa, &csa->ih)) { ac97_destroy(codec); csa_releaseres(csa, dev); return (ENXIO); } csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f); csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); + csa_active(csa, -1); if (pcm_register(dev, csa, 1, 1)) { ac97_destroy(codec); |