diff options
author | cg <cg@FreeBSD.org> | 2000-08-06 18:10:05 +0000 |
---|---|---|
committer | cg <cg@FreeBSD.org> | 2000-08-06 18:10:05 +0000 |
commit | 743aa0c1db42335c91c6b33060a3a377bc5d43ee (patch) | |
tree | ff4c76bc9b20bf20cc294cfeaba7c1631a34fefd | |
parent | 662a4ffb3c7874b13975dfc702267acd3c6e2b70 (diff) | |
download | FreeBSD-src-743aa0c1db42335c91c6b33060a3a377bc5d43ee.zip FreeBSD-src-743aa0c1db42335c91c6b33060a3a377bc5d43ee.tar.gz |
fix the staticy sound issue
use timer instead of per-channel interrupts
do playback like the linux driver - may fix nmi-with-ecc issue
-rw-r--r-- | sys/dev/sound/pci/emu10k1.c | 294 |
1 files changed, 140 insertions, 154 deletions
diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c index e598185..d31b21c 100644 --- a/sys/dev/sound/pci/emu10k1.c +++ b/sys/dev/sound/pci/emu10k1.c @@ -56,11 +56,11 @@ struct emu_mem { struct emu_voice { int vnum; - int b16:1, stereo:1, busy:1, ismaster:1, istracker:1; + int b16:1, stereo:1, busy:1, running:1, ismaster:1; int speed; int start, end, vol; u_int32_t buf; - struct emu_voice *slave, *tracker; + struct emu_voice *slave; pcm_channel *channel; }; @@ -69,7 +69,7 @@ struct sc_info; /* channel registers */ struct sc_pchinfo { int spd, fmt, run; - struct emu_voice *master, *slave, *tracker; + struct emu_voice *master, *slave; snd_dbuf *buffer; pcm_channel *channel; struct sc_info *parent; @@ -97,11 +97,12 @@ struct sc_info { int regtype, regid, irqid; void *ih; + int timer; int pnum, rnum; struct emu_mem mem; struct emu_voice voice[64]; struct sc_pchinfo pch[EMU_CHANS]; - struct sc_rchinfo rch[2]; + struct sc_rchinfo rch[3]; }; /* -------------------------------------------------------------------- */ @@ -264,6 +265,26 @@ emu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data) emu_wrptr(sc, 0, MICROCODEBASE + pc, data); } +/* ac97 codec */ +static u_int32_t +emu_rdcd(void *devinfo, int regno) +{ + struct sc_info *sc = (struct sc_info *)devinfo; + + emu_wr(sc, AC97ADDRESS, regno, 1); + return emu_rd(sc, AC97DATA, 2); +} + +static void +emu_wrcd(void *devinfo, int regno, u_int32_t data) +{ + struct sc_info *sc = (struct sc_info *)devinfo; + + emu_wr(sc, AC97ADDRESS, regno, 1); + emu_wr(sc, AC97DATA, data, 2); +} + +#if 0 /* playback channel interrupts */ static u_int32_t emu_testint(struct sc_info *sc, char channel) @@ -294,6 +315,28 @@ emu_enaint(struct sc_info *sc, char channel, int enable) reg |= channel << 16; emu_wrptr(sc, 0, reg, enable); } +#endif + +/* stuff */ +static int +emu_enatimer(struct sc_info *sc, int go) +{ + u_int32_t x; + if (go) { + if (sc->timer++ == 0) { + emu_wr(sc, TIMER, 256, 2); + x = emu_rd(sc, INTE, 4); + x |= INTE_INTERVALTIMERENB; + emu_wr(sc, INTE, x, 4); + } + } else { + sc->timer = 0; + x = emu_rd(sc, INTE, 4); + x &= ~INTE_INTERVALTIMERENB; + emu_wr(sc, INTE, x, 4); + } + return 0; +} static void emu_enastop(struct sc_info *sc, char channel, int enable) @@ -315,25 +358,6 @@ emu_recval(int speed) { return val; } -/* ac97 codec */ -static u_int32_t -emu_rdcd(void *devinfo, int regno) -{ - struct sc_info *sc = (struct sc_info *)devinfo; - - emu_wr(sc, AC97ADDRESS, regno, 1); - return emu_rd(sc, AC97DATA, 2); -} - -static void -emu_wrcd(void *devinfo, int regno, u_int32_t data) -{ - struct sc_info *sc = (struct sc_info *)devinfo; - - emu_wr(sc, AC97ADDRESS, regno, 1); - emu_wr(sc, AC97DATA, data, 2); -} - static u_int32_t emu_rate_to_pitch(u_int32_t rate) { @@ -391,6 +415,13 @@ emu_rate_to_pitch(u_int32_t rate) return 0; /* Should never reach this point */ } +static u_int32_t +emu_rate_to_linearpitch(u_int32_t rate) +{ + rate = (rate << 8) / 375; + return (rate >> 1) + (rate & 1); +} + static struct emu_voice * emu_valloc(struct sc_info *sc) { @@ -407,7 +438,7 @@ emu_valloc(struct sc_info *sc) } static int -emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s, struct emu_voice *t, +emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s, u_int32_t sz, pcm_channel *c) { void *buf; @@ -425,12 +456,11 @@ emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s, struct e m->speed = 0; m->b16 = 0; m->stereo = 0; + m->running = 0; m->ismaster = 1; - m->istracker = 0; m->vol = 0xff; m->buf = vtophys(buf); m->slave = s; - m->tracker = t; if (s != NULL) { s->start = m->start; s->end = m->end; @@ -438,26 +468,11 @@ emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s, struct e s->speed = 0; s->b16 = 0; s->stereo = 0; + s->running = 0; s->ismaster = 0; - s->istracker = 0; s->vol = m->vol; s->buf = m->buf; s->slave = NULL; - s->tracker = NULL; - } - if (t != NULL) { - t->start = m->start; - t->end = t->start + sz / 2; - t->channel = c; - t->speed = 0; - t->b16 = 0; - t->stereo = 0; - t->ismaster = 0; - t->istracker = 1; - t->vol = 0; - t->buf = m->buf; - t->slave = NULL; - t->tracker = NULL; } return 0; } @@ -474,148 +489,114 @@ emu_vsetup(struct sc_pchinfo *ch) v->slave->b16 = v->b16; v->slave->stereo = v->stereo; } - if (v->tracker != NULL) { - v->tracker->b16 = v->b16; - v->tracker->stereo = v->stereo; - } } if (ch->spd) { v->speed = ch->spd; if (v->slave != NULL) v->slave->speed = v->speed; - if (v->tracker != NULL) - v->tracker->speed = v->speed; } } static void emu_vwrite(struct sc_info *sc, struct emu_voice *v) { - int s, l, r, p, x; - u_int32_t sa, ea, start = 0, val = 0, v2 = 0, sample, silent_page, i; + int s; + int l, r, x, y; + u_int32_t sa, ea, start, val, silent_page; s = (v->stereo? 1 : 0) + (v->b16? 1 : 0); + sa = v->start >> s; ea = v->end >> s; - l = r = x = v->vol; + + l = r = x = y = v->vol; if (v->stereo) { l = v->ismaster? l : 0; r = v->ismaster? 0 : r; } - p = emu_rate_to_pitch(v->speed) >> 8; - sample = v->b16? 0 : 0x80808080; - emu_wrptr(sc, v->vnum, DCYSUSV, ENV_OFF); - emu_wrptr(sc, v->vnum, VTFT, VTFT_FILTERTARGET_MASK); - emu_wrptr(sc, v->vnum, CVCF, CVCF_CURRENTFILTER_MASK); + emu_wrptr(sc, v->vnum, CPF, v->stereo? CPF_STEREO_MASK : 0); + val = v->stereo? 28 : 30; + val *= v->b16? 1 : 2; + start = sa + val; + emu_wrptr(sc, v->vnum, FXRT, 0xd01c0000); emu_wrptr(sc, v->vnum, PTRX, (x << 8) | r); - if (v->ismaster) { - val = 0x20; - if (v->stereo) { - val <<= 1; - emu_wrptr(sc, v->vnum, CPF, CPF_STEREO_MASK); - emu_wrptr(sc, v->slave->vnum, CPF, CPF_STEREO_MASK); - } else - emu_wrptr(sc, v->vnum, CPF, 0); - sample = 0x80808080; - if (!v->b16) - val <<= 1; - val -= 4; - /* - * mono 8bit: val = 0x3c - * stereo 8bit: val = 0x7c - * mono 16bit: val = 0x1c - * stereo 16bit: val = 0x3c - */ - if (v->stereo) { - v2 = 0x3c << 16; - emu_wrptr(sc, v->vnum, CCR, v2); - emu_wrptr(sc, v->slave->vnum, CCR, val << 16); - emu_wrptr(sc, v->slave->vnum, CDE, sample); - emu_wrptr(sc, v->slave->vnum, CDF, sample); - start = sa + val / 2; - } else { - v2 = 0x1c << 16; - emu_wrptr(sc, v->vnum, CCR, v2); - emu_wrptr(sc, v->vnum, CDE, sample); - emu_wrptr(sc, v->vnum, CDF, sample); - start = sa + val; - } - val <<= 25; - val |= v2; - /* - * mono 8bit: val = 0x781c0000 - * stereo 8bit: val = 0xf83c0000 - * mono 16bit: val = 0x381c0000 - * stereo 16bit: val = 0x783c0000 - */ - start |= CCCA_INTERPROM_0; - } - emu_wrptr(sc, v->vnum, DSL, ea); + emu_wrptr(sc, v->vnum, DSL, ea | (y << 24)); emu_wrptr(sc, v->vnum, PSST, sa | (l << 24)); emu_wrptr(sc, v->vnum, CCCA, start | (v->b16? 0 : CCCA_8BITSELECT)); emu_wrptr(sc, v->vnum, Z1, 0); emu_wrptr(sc, v->vnum, Z2, 0); - silent_page = ((u_int32_t)v->buf << 1) | (v->start / EMUPAGESIZE); - /* silent_page = ((u_int32_t)vtophys(sc->mem.silent_page) << 1) | MAP_PTI_MASK; */ + silent_page = ((u_int32_t)vtophys(sc->mem.silent_page) << 1) | MAP_PTI_MASK; emu_wrptr(sc, v->vnum, MAPA, silent_page); emu_wrptr(sc, v->vnum, MAPB, silent_page); - if (v->ismaster) - emu_wrptr(sc, v->vnum, CCR, val); - - for (i = CD0; i < CDF; i++) - emu_wrptr(sc, v->vnum, i, sample); - - emu_wrptr(sc, v->vnum, ATKHLDV, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK); - emu_wrptr(sc, v->vnum, LFOVAL1, 0x8000); + emu_wrptr(sc, v->vnum, CVCF, CVCF_CURRENTFILTER_MASK); + emu_wrptr(sc, v->vnum, VTFT, VTFT_FILTERTARGET_MASK); emu_wrptr(sc, v->vnum, ATKHLDM, 0); emu_wrptr(sc, v->vnum, DCYSUSM, DCYSUSM_DECAYTIME_MASK); + emu_wrptr(sc, v->vnum, LFOVAL1, 0x8000); emu_wrptr(sc, v->vnum, LFOVAL2, 0x8000); - emu_wrptr(sc, v->vnum, IP, p); - emu_wrptr(sc, v->vnum, PEFE, 0x7f); emu_wrptr(sc, v->vnum, FMMOD, 0); emu_wrptr(sc, v->vnum, TREMFRQ, 0); emu_wrptr(sc, v->vnum, FM2FRQ2, 0); - emu_wrptr(sc, v->vnum, ENVVAL, 0xbfff); - emu_wrptr(sc, v->vnum, ENVVOL, 0xbfff); - emu_wrptr(sc, v->vnum, IFATN, IFATN_FILTERCUTOFF_MASK); + emu_wrptr(sc, v->vnum, ENVVAL, 0x8000); + + emu_wrptr(sc, v->vnum, ATKHLDV, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK); + emu_wrptr(sc, v->vnum, ENVVOL, 0x8000); + + emu_wrptr(sc, v->vnum, PEFE_FILTERAMOUNT, 0x7f); + emu_wrptr(sc, v->vnum, PEFE_PITCHAMOUNT, 0); if (v->slave != NULL) emu_vwrite(sc, v->slave); - if (v->tracker != NULL) - emu_vwrite(sc, v->tracker); } -#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL)) static void emu_vtrigger(struct sc_info *sc, struct emu_voice *v, int go) { - u_int32_t pitch_target; + u_int32_t pitch_target, initial_pitch; + u_int32_t cra, cs, ccis; + u_int32_t sample, i; + if (go) { - pitch_target = IP_TO_CP((emu_rate_to_pitch(v->speed) >> 8)) >> 16; + cra = 64; + cs = v->stereo? 4 : 2; + ccis = v->stereo? 28 : 30; + ccis *= v->b16? 1 : 2; + sample = v->b16? 0x00000000 : 0x80808080; + + for (i = 0; i < cs; i++) + emu_wrptr(sc, v->vnum, CD0 + i, sample); + emu_wrptr(sc, v->vnum, CCR_CACHEINVALIDSIZE, 0); + emu_wrptr(sc, v->vnum, CCR_READADDRESS, cra); + emu_wrptr(sc, v->vnum, CCR_CACHEINVALIDSIZE, ccis); + + emu_wrptr(sc, v->vnum, IFATN, 0xff00); + emu_wrptr(sc, v->vnum, VTFT, 0xffffffff); + emu_wrptr(sc, v->vnum, CVCF, 0xffffffff); + emu_wrptr(sc, v->vnum, DCYSUSV, 0x00007f7f); + emu_enastop(sc, v->vnum, 0); + + pitch_target = emu_rate_to_linearpitch(v->speed); + initial_pitch = emu_rate_to_pitch(v->speed) >> 8; emu_wrptr(sc, v->vnum, PTRX_PITCHTARGET, pitch_target); emu_wrptr(sc, v->vnum, CPF_CURRENTPITCH, pitch_target); - emu_wrptr(sc, v->vnum, VTFT, 0xffff); - emu_wrptr(sc, v->vnum, CVCF, 0xffff); - emu_enastop(sc, v->vnum, 0); - emu_enaint(sc, v->vnum, v->istracker); - emu_wrptr(sc, v->vnum, DCYSUSV, ENV_ON | 0x00007f7f); + emu_wrptr(sc, v->vnum, IP, initial_pitch); } else { + emu_wrptr(sc, v->vnum, PTRX_PITCHTARGET, 0); + emu_wrptr(sc, v->vnum, CPF_CURRENTPITCH, 0); emu_wrptr(sc, v->vnum, IFATN, 0xffff); + emu_wrptr(sc, v->vnum, VTFT, 0x0000ffff); + emu_wrptr(sc, v->vnum, CVCF, 0x0000ffff); emu_wrptr(sc, v->vnum, IP, 0); - emu_wrptr(sc, v->vnum, VTFT, 0xffff); - emu_wrptr(sc, v->vnum, CPF_CURRENTPITCH, 0); - emu_enaint(sc, v->vnum, 0); + emu_enastop(sc, v->vnum, 1); } if (v->slave != NULL) emu_vtrigger(sc, v->slave, go); - if (v->tracker != NULL) - emu_vtrigger(sc, v->tracker, go); } static int @@ -624,8 +605,8 @@ emu_vpos(struct sc_info *sc, struct emu_voice *v) int s, ptr; s = (v->b16? 1 : 0) + (v->stereo? 1 : 0); - ptr = (emu_rdptr(sc, v->vnum, CCCA_CURRADDR) << s) - v->start; - return ptr; + ptr = (emu_rdptr(sc, v->vnum, CCCA_CURRADDR) - (v->start >> s)) << s; + return ptr & ~0x0000001f; } #ifdef EMUDEBUG @@ -668,8 +649,7 @@ emupchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) ch->channel = c; ch->master = emu_valloc(sc); ch->slave = emu_valloc(sc); - ch->tracker = emu_valloc(sc); - if (emu_vinit(sc, ch->master, ch->slave, ch->tracker, EMU_BUFFSIZE, ch->channel)) + if (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->channel)) return NULL; else return ch; @@ -717,6 +697,7 @@ emupchan_trigger(void *data, int go) if (go == PCMTRIG_START) { emu_vsetup(ch); emu_vwrite(sc, ch->master); + emu_enatimer(sc, 1); #ifdef EMUDEBUG printf("start [%d bit, %s, %d hz]\n", ch->master->b16? 16 : 8, @@ -753,7 +734,7 @@ emurchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) struct sc_info *sc = devinfo; struct sc_rchinfo *ch; - KASSERT(dir == PCMDIR_REC, ("emupchan_init: bad direction")); + KASSERT(dir == PCMDIR_REC, ("emurchan_init: bad direction")); ch = &sc->rch[sc->rnum]; ch->buffer = b; ch->buffer->bufsize = EMU_BUFFSIZE; @@ -899,7 +880,7 @@ static void emu_intr(void *p) { struct sc_info *sc = (struct sc_info *)p; - u_int32_t stat, ack, i; + u_int32_t stat, ack, i, x; while (1) { stat = emu_rd(sc, IPR, 4); @@ -908,21 +889,20 @@ emu_intr(void *p) ack = 0; /* process irq */ - if (stat & IPR_CHANNELLOOP) { - ack |= IPR_CHANNELLOOP | (stat & IPR_CHANNELNUMBERMASK); - for (i = 0; i < 64; i++) { - if (emu_testint(sc, i)) { - if (sc->voice[i].channel) - chn_intr(sc->voice[i].channel); - else { - device_printf(sc->dev, "bad irq voice %d\n", i); - emu_enaint(sc, i, 0); - } - emu_clrint(sc, i); + if (stat & IPR_INTERVALTIMER) { + ack |= IPR_INTERVALTIMER; + x = 0; + for (i = 0; i < EMU_CHANS; i++) { + if (sc->pch[i].run) { + x = 1; + chn_intr(sc->pch[i].channel); } } + if (x == 0) + emu_enatimer(sc, 0); } + if (stat & (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL)) { ack |= stat & (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL); if (sc->rch[0].channel) @@ -941,10 +921,15 @@ emu_intr(void *p) if (stat & IPR_PCIERROR) { ack |= IPR_PCIERROR; device_printf(sc->dev, "pci error\n"); + /* we still get an nmi with ecc ram even if we ack this */ + } + if (stat & IPR_SAMPLERATETRACKER) { + ack |= IPR_SAMPLERATETRACKER; + device_printf(sc->dev, "sample rate tracker lock status change\n"); } if (stat & ~ack) - device_printf(sc->dev, "dodgy irq: %x\n", stat & ~ack); + device_printf(sc->dev, "dodgy irq: %x (harmless)\n", stat & ~ack); emu_wr(sc, IPR, stat, 4); } @@ -999,7 +984,7 @@ emu_memalloc(struct sc_info *sc, u_int32_t sz) blksz++; /* find a free block in the bitmap */ found = 0; - start = 0; + start = 1; while (!found && start + blksz < MAXPAGES) { found = 1; for (idx = start; idx < start + blksz; idx++) @@ -1179,15 +1164,15 @@ emu_init(struct sc_info *sc) emu_wr(sc, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE, 4); /* reset recording buffers */ - emu_wrptr(sc, 0, MICBS, 0); + emu_wrptr(sc, 0, MICBS, ADCBS_BUFSIZE_NONE); emu_wrptr(sc, 0, MICBA, 0); - emu_wrptr(sc, 0, FXBS, 0); + emu_wrptr(sc, 0, FXBS, ADCBS_BUFSIZE_NONE); emu_wrptr(sc, 0, FXBA, 0); emu_wrptr(sc, 0, ADCBS, ADCBS_BUFSIZE_NONE); emu_wrptr(sc, 0, ADCBA, 0); /* disable channel interrupt */ - emu_wr(sc, INTE, INTE_SAMPLERATETRACKER | INTE_PCIERRORENABLE, 4); + emu_wr(sc, INTE, INTE_INTERVALTIMERENB | INTE_SAMPLERATETRACKER | INTE_PCIERRORENABLE, 4); emu_wrptr(sc, 0, CLIEL, 0); emu_wrptr(sc, 0, CLIEH, 0); emu_wrptr(sc, 0, SOLEL, 0); @@ -1228,10 +1213,9 @@ emu_init(struct sc_info *sc) sc->voice[ch].vnum = ch; sc->voice[ch].slave = NULL; - sc->voice[ch].tracker = NULL; sc->voice[ch].busy = 0; sc->voice[ch].ismaster = 0; - sc->voice[ch].istracker = 0; + sc->voice[ch].running = 0; sc->voice[ch].b16 = 0; sc->voice[ch].stereo = 0; sc->voice[ch].speed = 0; @@ -1283,7 +1267,7 @@ emu_init(struct sc_info *sc) emu_wrptr(sc, 0, PTB, vtophys(sc->mem.ptb_pages)); emu_wrptr(sc, 0, TCB, 0); /* taken from original driver */ - emu_wrptr(sc, 0, TCBS, 4); /* taken from original driver */ + emu_wrptr(sc, 0, TCBS, 0); /* taken from original driver */ for (ch = 0; ch < NUM_G; ch++) { emu_wrptr(sc, ch, MAPA, tmp | MAP_PTI_MASK); @@ -1434,6 +1418,7 @@ bad: return ENXIO; } +/* add suspend, resume, unload */ static device_method_t emu_methods[] = { /* Device interface */ DEVMETHOD(device_probe, emu_pci_probe), @@ -1454,6 +1439,7 @@ DRIVER_MODULE(snd_emu10k1, pci, emu_driver, pcm_devclass, 0, 0); MODULE_DEPEND(snd_emu10k1, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); MODULE_VERSION(snd_emu10k1, 1); +/* dummy driver to silence the joystick device */ static int emujoy_pci_probe(device_t dev) { |