Index: head/sys/dev/sound/pci/emu10k1.c =================================================================== --- head/sys/dev/sound/pci/emu10k1.c (revision 124276) +++ head/sys/dev/sound/pci/emu10k1.c (revision 124277) @@ -1,1637 +1,1644 @@ /* + * Copyright (c) 2004 David O'Brien * Copyright (c) 1999 Cameron Grant * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include SND_DECLARE_FILE("$FreeBSD$"); /* -------------------------------------------------------------------- */ +#define NUM_G 64 /* use all channels */ +#define WAVEOUT_MAXBUFSIZE 32768 +#define EMUPAGESIZE 4096 /* don't change */ +#define MAXPAGES (WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE) #define EMU10K1_PCI_ID 0x00021102 #define EMU10K2_PCI_ID 0x00041102 #define EMU_DEFAULT_BUFSZ 4096 #define EMU_CHANS 4 +#define ENV_ON DCYSUSV_CHANNELENABLE_MASK +#define ENV_OFF 0x00 /* XXX: should this be 1? */ #undef EMUDEBUG struct emu_memblk { SLIST_ENTRY(emu_memblk) link; void *buf; bus_addr_t buf_addr; u_int32_t pte_start, pte_size; }; struct emu_mem { u_int8_t bmap[MAXPAGES / 8]; u_int32_t *ptb_pages; void *silent_page; bus_addr_t silent_page_addr; bus_addr_t ptb_pages_addr; SLIST_HEAD(, emu_memblk) blocks; }; struct emu_voice { int vnum; 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; struct pcm_channel *channel; }; struct sc_info; /* channel registers */ struct sc_pchinfo { int spd, fmt, blksz, run; struct emu_voice *master, *slave; struct snd_dbuf *buffer; struct pcm_channel *channel; struct sc_info *parent; }; struct sc_rchinfo { int spd, fmt, run, blksz, num; u_int32_t idxreg, basereg, sizereg, setupreg, irqmask; struct snd_dbuf *buffer; struct pcm_channel *channel; struct sc_info *parent; }; /* device private data */ struct sc_info { device_t dev; u_int32_t type, rev; u_int32_t tos_link:1, APS:1; bus_space_tag_t st; bus_space_handle_t sh; bus_dma_tag_t parent_dmat; struct resource *reg, *irq; void *ih; struct mtx *lock; unsigned int bufsz; int timer, timerinterval; int pnum, rnum; struct emu_mem mem; struct emu_voice voice[64]; struct sc_pchinfo pch[EMU_CHANS]; struct sc_rchinfo rch[3]; }; /* -------------------------------------------------------------------- */ /* * prototypes */ /* stuff */ static int emu_init(struct sc_info *); static void emu_intr(void *); static void *emu_malloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr); static void *emu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr); static int emu_memfree(struct sc_info *sc, void *buf); static int emu_memstart(struct sc_info *sc, void *buf); #ifdef EMUDEBUG static void emu_vdump(struct sc_info *sc, struct emu_voice *v); #endif /* talk to the card */ static u_int32_t emu_rd(struct sc_info *, int, int); static void emu_wr(struct sc_info *, int, u_int32_t, int); /* -------------------------------------------------------------------- */ static u_int32_t emu_rfmt_ac97[] = { AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE, 0 }; static u_int32_t emu_rfmt_mic[] = { AFMT_U8, 0 }; static u_int32_t emu_rfmt_efx[] = { AFMT_STEREO | AFMT_S16_LE, 0 }; static struct pcmchan_caps emu_reccaps[3] = { {8000, 48000, emu_rfmt_ac97, 0}, {8000, 8000, emu_rfmt_mic, 0}, {48000, 48000, emu_rfmt_efx, 0}, }; static u_int32_t emu_pfmt[] = { AFMT_U8, AFMT_STEREO | AFMT_U8, AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE, 0 }; static struct pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0}; static int adcspeed[8] = {48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}; /* -------------------------------------------------------------------- */ /* Hardware */ static u_int32_t emu_rd(struct sc_info *sc, int regno, int size) { switch (size) { case 1: return bus_space_read_1(sc->st, sc->sh, regno); case 2: return bus_space_read_2(sc->st, sc->sh, regno); case 4: return bus_space_read_4(sc->st, sc->sh, regno); default: return 0xffffffff; } } static void emu_wr(struct sc_info *sc, int regno, u_int32_t data, int size) { switch (size) { case 1: bus_space_write_1(sc->st, sc->sh, regno, data); break; case 2: bus_space_write_2(sc->st, sc->sh, regno, data); break; case 4: bus_space_write_4(sc->st, sc->sh, regno, data); break; } } static u_int32_t emu_rdptr(struct sc_info *sc, int chn, int reg) { u_int32_t ptr, val, mask, size, offset; ptr = ((reg << 16) & PTR_ADDRESS_MASK) | (chn & PTR_CHANNELNUM_MASK); emu_wr(sc, PTR, ptr, 4); val = emu_rd(sc, DATA, 4); if (reg & 0xff000000) { size = (reg >> 24) & 0x3f; offset = (reg >> 16) & 0x1f; mask = ((1 << size) - 1) << offset; val &= mask; val >>= offset; } return val; } static void emu_wrptr(struct sc_info *sc, int chn, int reg, u_int32_t data) { u_int32_t ptr, mask, size, offset; ptr = ((reg << 16) & PTR_ADDRESS_MASK) | (chn & PTR_CHANNELNUM_MASK); emu_wr(sc, PTR, ptr, 4); if (reg & 0xff000000) { size = (reg >> 24) & 0x3f; offset = (reg >> 16) & 0x1f; mask = ((1 << size) - 1) << offset; data <<= offset; data &= mask; data |= emu_rd(sc, DATA, 4) & ~mask; } emu_wr(sc, DATA, data, 4); } static void emu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data) { emu_wrptr(sc, 0, MICROCODEBASE + pc, data); } /* -------------------------------------------------------------------- */ /* ac97 codec */ /* no locking needed */ static int emu_rdcd(kobj_t obj, 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 int emu_wrcd(kobj_t obj, 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); return 0; } static kobj_method_t emu_ac97_methods[] = { KOBJMETHOD(ac97_read, emu_rdcd), KOBJMETHOD(ac97_write, emu_wrcd), { 0, 0 } }; AC97_DECLARE(emu_ac97); /* -------------------------------------------------------------------- */ /* stuff */ static int emu_settimer(struct sc_info *sc) { struct sc_pchinfo *pch; struct sc_rchinfo *rch; int i, tmp, rate; rate = 0; for (i = 0; i < EMU_CHANS; i++) { pch = &sc->pch[i]; if (pch->buffer) { tmp = (pch->spd * sndbuf_getbps(pch->buffer)) / pch->blksz; if (tmp > rate) rate = tmp; } } for (i = 0; i < 3; i++) { rch = &sc->rch[i]; if (rch->buffer) { tmp = (rch->spd * sndbuf_getbps(rch->buffer)) / rch->blksz; if (tmp > rate) rate = tmp; } } RANGE(rate, 48, 9600); sc->timerinterval = 48000 / rate; emu_wr(sc, TIMER, sc->timerinterval & 0x03ff, 2); return sc->timerinterval; } static int emu_enatimer(struct sc_info *sc, int go) { u_int32_t x; if (go) { if (sc->timer++ == 0) { 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) { int reg = (channel & 0x20) ? SOLEH : SOLEL; channel &= 0x1f; reg |= 1 << 24; reg |= channel << 16; emu_wrptr(sc, 0, reg, enable); } static int emu_recval(int speed) { int val; val = 0; while (val < 7 && speed < adcspeed[val]) val++; return val; } static u_int32_t emu_rate_to_pitch(u_int32_t rate) { static u_int32_t logMagTable[128] = { 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df }; static char logSlopeTable[128] = { 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f }; int i; if (rate == 0) return 0; /* Bail out if no leading "1" */ rate *= 11185; /* Scale 48000 to 0x20002380 */ for (i = 31; i > 0; i--) { if (rate & 0x80000000) { /* Detect leading "1" */ return (((u_int32_t) (i - 15) << 20) + logMagTable[0x7f & (rate >> 24)] + (0x7f & (rate >> 17)) * logSlopeTable[0x7f & (rate >> 24)]); } rate <<= 1; } 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) { struct emu_voice *v; int i; v = NULL; for (i = 0; i < 64 && sc->voice[i].busy; i++); if (i < 64) { v = &sc->voice[i]; v->busy = 1; } return v; } static int emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s, u_int32_t sz, struct snd_dbuf *b) { void *buf; bus_addr_t tmp_addr; buf = emu_memalloc(sc, sz, &tmp_addr); if (buf == NULL) return -1; if (b != NULL) sndbuf_setup(b, buf, sz); m->start = emu_memstart(sc, buf) * EMUPAGESIZE; m->end = m->start + sz; m->channel = NULL; m->speed = 0; m->b16 = 0; m->stereo = 0; m->running = 0; m->ismaster = 1; m->vol = 0xff; m->buf = tmp_addr; m->slave = s; if (s != NULL) { s->start = m->start; s->end = m->end; s->channel = NULL; s->speed = 0; s->b16 = 0; s->stereo = 0; s->running = 0; s->ismaster = 0; s->vol = m->vol; s->buf = m->buf; s->slave = NULL; } return 0; } static void emu_vsetup(struct sc_pchinfo *ch) { struct emu_voice *v = ch->master; if (ch->fmt) { v->b16 = (ch->fmt & AFMT_16BIT) ? 1 : 0; v->stereo = (ch->fmt & AFMT_STEREO) ? 1 : 0; if (v->slave != NULL) { v->slave->b16 = v->b16; v->slave->stereo = v->stereo; } } if (ch->spd) { v->speed = ch->spd; if (v->slave != NULL) v->slave->speed = v->speed; } } static void emu_vwrite(struct sc_info *sc, struct emu_voice *v) { 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 = y = v->vol; if (v->stereo) { l = v->ismaster ? l : 0; r = v->ismaster ? 0 : r; } 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); 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)(sc->mem.silent_page_addr) << 1) | MAP_PTI_MASK; emu_wrptr(sc, v->vnum, MAPA, silent_page); emu_wrptr(sc, v->vnum, MAPB, silent_page); 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, FMMOD, 0); emu_wrptr(sc, v->vnum, TREMFRQ, 0); emu_wrptr(sc, v->vnum, FM2FRQ2, 0); 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); } static void emu_vtrigger(struct sc_info *sc, struct emu_voice *v, int go) { u_int32_t pitch_target, initial_pitch; u_int32_t cra, cs, ccis; u_int32_t sample, i; if (go) { 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, 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_enastop(sc, v->vnum, 1); } if (v->slave != NULL) emu_vtrigger(sc, v->slave, go); } static int 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) - (v->start >> s)) << s; return ptr & ~0x0000001f; } #ifdef EMUDEBUG static void emu_vdump(struct sc_info *sc, struct emu_voice *v) { char *regname[] = { "cpf", "ptrx", "cvcf", "vtft", "z2", "z1", "psst", "dsl", "ccca", "ccr", "clp", "fxrt", "mapa", "mapb", NULL, NULL, "envvol", "atkhldv", "dcysusv", "lfoval1", "envval", "atkhldm", "dcysusm", "lfoval2", "ip", "ifatn", "pefe", "fmmod", "tremfrq", "fmfrq2", "tempenv" }; int i, x; printf("voice number %d\n", v->vnum); for (i = 0, x = 0; i <= 0x1e; i++) { if (regname[i] == NULL) continue; printf("%s\t[%08x]", regname[i], emu_rdptr(sc, v->vnum, i)); printf("%s", (x == 2) ? "\n" : "\t"); x++; if (x > 2) x = 0; } printf("\n\n"); } #endif /* channel interface */ static void * emupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_pchinfo *ch; void *r; KASSERT(dir == PCMDIR_PLAY, ("emupchan_init: bad direction")); ch = &sc->pch[sc->pnum++]; ch->buffer = b; ch->parent = sc; ch->channel = c; ch->blksz = sc->bufsz / 2; ch->fmt = AFMT_U8; ch->spd = 8000; snd_mtxlock(sc->lock); ch->master = emu_valloc(sc); ch->slave = emu_valloc(sc); snd_mtxunlock(sc->lock); r = (emu_vinit(sc, ch->master, ch->slave, sc->bufsz, ch->buffer)) ? NULL : ch; return r; } static int emupchan_free(kobj_t obj, void *data) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; int r; snd_mtxlock(sc->lock); r = emu_memfree(sc, sndbuf_getbuf(ch->buffer)); snd_mtxunlock(sc->lock); return r; } static int emupchan_setformat(kobj_t obj, void *data, u_int32_t format) { struct sc_pchinfo *ch = data; ch->fmt = format; return 0; } static int emupchan_setspeed(kobj_t obj, void *data, u_int32_t speed) { struct sc_pchinfo *ch = data; ch->spd = speed; return ch->spd; } static int emupchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; int irqrate, blksz; ch->blksz = blocksize; snd_mtxlock(sc->lock); emu_settimer(sc); irqrate = 48000 / sc->timerinterval; snd_mtxunlock(sc->lock); blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate; return blocksize; } static int emupchan_trigger(kobj_t obj, void *data, int go) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0; snd_mtxlock(sc->lock); if (go == PCMTRIG_START) { emu_vsetup(ch); emu_vwrite(sc, ch->master); emu_settimer(sc); emu_enatimer(sc, 1); #ifdef EMUDEBUG printf("start [%d bit, %s, %d hz]\n", ch->master->b16 ? 16 : 8, ch->master->stereo ? "stereo" : "mono", ch->master->speed); emu_vdump(sc, ch->master); emu_vdump(sc, ch->slave); #endif } ch->run = (go == PCMTRIG_START) ? 1 : 0; emu_vtrigger(sc, ch->master, ch->run); snd_mtxunlock(sc->lock); return 0; } static int emupchan_getptr(kobj_t obj, void *data) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; int r; snd_mtxlock(sc->lock); r = emu_vpos(sc, ch->master); snd_mtxunlock(sc->lock); return r; } static struct pcmchan_caps * emupchan_getcaps(kobj_t obj, void *data) { return &emu_playcaps; } static kobj_method_t emupchan_methods[] = { KOBJMETHOD(channel_init, emupchan_init), KOBJMETHOD(channel_free, emupchan_free), KOBJMETHOD(channel_setformat, emupchan_setformat), KOBJMETHOD(channel_setspeed, emupchan_setspeed), KOBJMETHOD(channel_setblocksize, emupchan_setblocksize), KOBJMETHOD(channel_trigger, emupchan_trigger), KOBJMETHOD(channel_getptr, emupchan_getptr), KOBJMETHOD(channel_getcaps, emupchan_getcaps), { 0, 0 } }; CHANNEL_DECLARE(emupchan); /* channel interface */ static void * emurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_rchinfo *ch; KASSERT(dir == PCMDIR_REC, ("emurchan_init: bad direction")); ch = &sc->rch[sc->rnum]; ch->buffer = b; ch->parent = sc; ch->channel = c; ch->blksz = sc->bufsz / 2; ch->fmt = AFMT_U8; ch->spd = 8000; ch->num = sc->rnum; switch(sc->rnum) { case 0: ch->idxreg = ADCIDX; ch->basereg = ADCBA; ch->sizereg = ADCBS; ch->setupreg = ADCCR; ch->irqmask = INTE_ADCBUFENABLE; break; case 1: ch->idxreg = FXIDX; ch->basereg = FXBA; ch->sizereg = FXBS; ch->setupreg = FXWC; ch->irqmask = INTE_EFXBUFENABLE; break; case 2: ch->idxreg = MICIDX; ch->basereg = MICBA; ch->sizereg = MICBS; ch->setupreg = 0; ch->irqmask = INTE_MICBUFENABLE; break; } sc->rnum++; if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) == -1) return NULL; else { snd_mtxlock(sc->lock); emu_wrptr(sc, 0, ch->basereg, sndbuf_getbufaddr(ch->buffer)); emu_wrptr(sc, 0, ch->sizereg, 0); /* off */ snd_mtxunlock(sc->lock); return ch; } } static int emurchan_setformat(kobj_t obj, void *data, u_int32_t format) { struct sc_rchinfo *ch = data; ch->fmt = format; return 0; } static int emurchan_setspeed(kobj_t obj, void *data, u_int32_t speed) { struct sc_rchinfo *ch = data; if (ch->num == 0) speed = adcspeed[emu_recval(speed)]; if (ch->num == 1) speed = 48000; if (ch->num == 2) speed = 8000; ch->spd = speed; return ch->spd; } static int emurchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) { struct sc_rchinfo *ch = data; struct sc_info *sc = ch->parent; int irqrate, blksz; ch->blksz = blocksize; snd_mtxlock(sc->lock); emu_settimer(sc); irqrate = 48000 / sc->timerinterval; snd_mtxunlock(sc->lock); blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate; return blocksize; } /* semantic note: must start at beginning of buffer */ static int emurchan_trigger(kobj_t obj, void *data, int go) { struct sc_rchinfo *ch = data; struct sc_info *sc = ch->parent; u_int32_t val, sz; switch(sc->bufsz) { case 4096: sz = ADCBS_BUFSIZE_4096; break; case 8192: sz = ADCBS_BUFSIZE_8192; break; case 16384: sz = ADCBS_BUFSIZE_16384; break; case 32768: sz = ADCBS_BUFSIZE_32768; break; case 65536: sz = ADCBS_BUFSIZE_65536; break; default: sz = ADCBS_BUFSIZE_4096; } snd_mtxlock(sc->lock); switch(go) { case PCMTRIG_START: ch->run = 1; emu_wrptr(sc, 0, ch->sizereg, sz); if (ch->num == 0) { val = ADCCR_LCHANENABLE; if (ch->fmt & AFMT_STEREO) val |= ADCCR_RCHANENABLE; val |= emu_recval(ch->spd); emu_wrptr(sc, 0, ch->setupreg, 0); emu_wrptr(sc, 0, ch->setupreg, val); } val = emu_rd(sc, INTE, 4); val |= ch->irqmask; emu_wr(sc, INTE, val, 4); break; case PCMTRIG_STOP: case PCMTRIG_ABORT: ch->run = 0; emu_wrptr(sc, 0, ch->sizereg, 0); if (ch->setupreg) emu_wrptr(sc, 0, ch->setupreg, 0); val = emu_rd(sc, INTE, 4); val &= ~ch->irqmask; emu_wr(sc, INTE, val, 4); break; case PCMTRIG_EMLDMAWR: case PCMTRIG_EMLDMARD: default: break; } snd_mtxunlock(sc->lock); return 0; } static int emurchan_getptr(kobj_t obj, void *data) { struct sc_rchinfo *ch = data; struct sc_info *sc = ch->parent; int r; snd_mtxlock(sc->lock); r = emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff; snd_mtxunlock(sc->lock); return r; } static struct pcmchan_caps * emurchan_getcaps(kobj_t obj, void *data) { struct sc_rchinfo *ch = data; return &emu_reccaps[ch->num]; } static kobj_method_t emurchan_methods[] = { KOBJMETHOD(channel_init, emurchan_init), KOBJMETHOD(channel_setformat, emurchan_setformat), KOBJMETHOD(channel_setspeed, emurchan_setspeed), KOBJMETHOD(channel_setblocksize, emurchan_setblocksize), KOBJMETHOD(channel_trigger, emurchan_trigger), KOBJMETHOD(channel_getptr, emurchan_getptr), KOBJMETHOD(channel_getcaps, emurchan_getcaps), { 0, 0 } }; CHANNEL_DECLARE(emurchan); /* -------------------------------------------------------------------- */ /* The interrupt handler */ static void emu_intr(void *p) { struct sc_info *sc = (struct sc_info *)p; u_int32_t stat, ack, i, x; while (1) { stat = emu_rd(sc, IPR, 4); if (stat == 0) break; ack = 0; /* process irq */ 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) chn_intr(sc->rch[0].channel); } if (stat & (IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)) { ack |= stat & (IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL); if (sc->rch[1].channel) chn_intr(sc->rch[1].channel); } if (stat & (IPR_MICBUFFULL | IPR_MICBUFHALFFULL)) { ack |= stat & (IPR_MICBUFFULL | IPR_MICBUFHALFFULL); if (sc->rch[2].channel) chn_intr(sc->rch[2].channel); } 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 (harmless)\n", stat & ~ack); emu_wr(sc, IPR, stat, 4); } } /* -------------------------------------------------------------------- */ static void emu_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) { bus_addr_t *phys = arg; *phys = error ? 0 : (bus_addr_t)segs->ds_addr; if (bootverbose) { printf("emu: setmap (%lx, %lx), nseg=%d, error=%d\n", (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len, nseg, error); } } static void * emu_malloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr) { void *buf; bus_dmamap_t map; *addr = 0; if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &map)) return NULL; if (bus_dmamap_load(sc->parent_dmat, map, buf, sz, emu_setmap, addr, 0) || !*addr) return NULL; return buf; } static void emu_free(struct sc_info *sc, void *buf) { bus_dmamem_free(sc->parent_dmat, buf, NULL); } static void * emu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr) { u_int32_t blksz, start, idx, ofs, tmp, found; struct emu_mem *mem = &sc->mem; struct emu_memblk *blk; void *buf; blksz = sz / EMUPAGESIZE; if (sz > (blksz * EMUPAGESIZE)) blksz++; /* find a free block in the bitmap */ found = 0; start = 1; while (!found && start + blksz < MAXPAGES) { found = 1; for (idx = start; idx < start + blksz; idx++) if (mem->bmap[idx >> 3] & (1 << (idx & 7))) found = 0; if (!found) start++; } if (!found) return NULL; blk = malloc(sizeof(*blk), M_DEVBUF, M_NOWAIT); if (blk == NULL) return NULL; buf = emu_malloc(sc, sz, &blk->buf_addr); *addr = blk->buf_addr; if (buf == NULL) { free(blk, M_DEVBUF); return NULL; } blk->buf = buf; blk->pte_start = start; blk->pte_size = blksz; /* printf("buf %p, pte_start %d, pte_size %d\n", blk->buf, blk->pte_start, blk->pte_size); */ ofs = 0; for (idx = start; idx < start + blksz; idx++) { mem->bmap[idx >> 3] |= 1 << (idx & 7); tmp = (u_int32_t)(u_long)((u_int8_t *)blk->buf_addr + ofs); /* printf("pte[%d] -> %x phys, %x virt\n", idx, tmp, ((u_int32_t)buf) + ofs); */ mem->ptb_pages[idx] = (tmp << 1) | idx; ofs += EMUPAGESIZE; } SLIST_INSERT_HEAD(&mem->blocks, blk, link); return buf; } static int emu_memfree(struct sc_info *sc, void *buf) { u_int32_t idx, tmp; struct emu_mem *mem = &sc->mem; struct emu_memblk *blk, *i; blk = NULL; SLIST_FOREACH(i, &mem->blocks, link) { if (i->buf == buf) blk = i; } if (blk == NULL) return EINVAL; SLIST_REMOVE(&mem->blocks, blk, emu_memblk, link); emu_free(sc, buf); tmp = (u_int32_t)(sc->mem.silent_page_addr) << 1; for (idx = blk->pte_start; idx < blk->pte_start + blk->pte_size; idx++) { mem->bmap[idx >> 3] &= ~(1 << (idx & 7)); mem->ptb_pages[idx] = tmp | idx; } free(blk, M_DEVBUF); return 0; } static int emu_memstart(struct sc_info *sc, void *buf) { struct emu_mem *mem = &sc->mem; struct emu_memblk *blk, *i; blk = NULL; SLIST_FOREACH(i, &mem->blocks, link) { if (i->buf == buf) blk = i; } if (blk == NULL) return -EINVAL; return blk->pte_start; } static void emu_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y, u_int32_t *pc) { emu_wrefx(sc, (*pc) * 2, (x << 10) | y); emu_wrefx(sc, (*pc) * 2 + 1, (op << 20) | (z << 10) | w); (*pc)++; } static void emu_initefx(struct sc_info *sc) { int i; u_int32_t pc = 16; for (i = 0; i < 512; i++) { emu_wrefx(sc, i * 2, 0x10040); emu_wrefx(sc, i * 2 + 1, 0x610040); } for (i = 0; i < 256; i++) emu_wrptr(sc, 0, FXGPREGBASE + i, 0); /* FX-8010 DSP Registers: FX Bus 0x000-0x00f : 16 registers Input 0x010/0x011 : AC97 Codec (l/r) 0x012/0x013 : ADC, S/PDIF (l/r) 0x014/0x015 : Mic(left), Zoom (l/r) 0x016/0x017 : APS S/PDIF?? (l/r) Output 0x020/0x021 : AC97 Output (l/r) 0x022/0x023 : TOS link out (l/r) 0x024/0x025 : ??? (l/r) 0x026/0x027 : LiveDrive Headphone (l/r) 0x028/0x029 : Rear Channel (l/r) 0x02a/0x02b : ADC Recording Buffer (l/r) Constants 0x040 - 0x044 = 0 - 4 0x045 = 0x8, 0x046 = 0x10, 0x047 = 0x20 0x048 = 0x100, 0x049 = 0x10000, 0x04a = 0x80000 0x04b = 0x10000000, 0x04c = 0x20000000, 0x04d = 0x40000000 0x04e = 0x80000000, 0x04f = 0x7fffffff Temporary Values 0x056 : Accumulator 0x058 : Noise source? 0x059 : Noise source? General Purpose Registers 0x100 - 0x1ff Tank Memory Data Registers 0x200 - 0x2ff Tank Memory Address Registers 0x300 - 0x3ff */ /* Operators: 0 : z := w + (x * y >> 31) 4 : z := w + x * y 6 : z := w + x + y */ /* Routing - this will be configurable in later version */ /* GPR[0/1] = FX * 4 + SPDIF-in */ emu_addefxop(sc, 4, 0x100, 0x12, 0, 0x44, &pc); emu_addefxop(sc, 4, 0x101, 0x13, 1, 0x44, &pc); /* GPR[0/1] += APS-input */ emu_addefxop(sc, 6, 0x100, 0x100, 0x40, sc->APS ? 0x16 : 0x40, &pc); emu_addefxop(sc, 6, 0x101, 0x101, 0x40, sc->APS ? 0x17 : 0x40, &pc); /* FrontOut (AC97) = GPR[0/1] */ emu_addefxop(sc, 6, 0x20, 0x40, 0x40, 0x100, &pc); emu_addefxop(sc, 6, 0x21, 0x40, 0x41, 0x101, &pc); /* RearOut = (GPR[0/1] * RearVolume) >> 31 */ /* RearVolume = GRP[0x10/0x11] */ emu_addefxop(sc, 0, 0x28, 0x40, 0x110, 0x100, &pc); emu_addefxop(sc, 0, 0x29, 0x40, 0x111, 0x101, &pc); /* TOS out = GPR[0/1] */ emu_addefxop(sc, 6, 0x22, 0x40, 0x40, 0x100, &pc); emu_addefxop(sc, 6, 0x23, 0x40, 0x40, 0x101, &pc); /* Mute Out2 */ emu_addefxop(sc, 6, 0x24, 0x40, 0x40, 0x40, &pc); emu_addefxop(sc, 6, 0x25, 0x40, 0x40, 0x40, &pc); /* Mute Out3 */ emu_addefxop(sc, 6, 0x26, 0x40, 0x40, 0x40, &pc); emu_addefxop(sc, 6, 0x27, 0x40, 0x40, 0x40, &pc); /* Input0 (AC97) -> Record */ emu_addefxop(sc, 6, 0x2a, 0x40, 0x40, 0x10, &pc); emu_addefxop(sc, 6, 0x2b, 0x40, 0x40, 0x11, &pc); emu_wrptr(sc, 0, DBG, 0); } /* Probe and attach the card */ static int emu_init(struct sc_info *sc) { u_int32_t spcs, ch, tmp, i; /* disable audio and lock cache */ emu_wr(sc, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, 4); /* reset recording buffers */ emu_wrptr(sc, 0, MICBS, ADCBS_BUFSIZE_NONE); emu_wrptr(sc, 0, MICBA, 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_INTERVALTIMERENB | INTE_SAMPLERATETRACKER | INTE_PCIERRORENABLE, 4); emu_wrptr(sc, 0, CLIEL, 0); emu_wrptr(sc, 0, CLIEH, 0); emu_wrptr(sc, 0, SOLEL, 0); emu_wrptr(sc, 0, SOLEH, 0); /* init envelope engine */ for (ch = 0; ch < NUM_G; ch++) { emu_wrptr(sc, ch, DCYSUSV, ENV_OFF); emu_wrptr(sc, ch, IP, 0); emu_wrptr(sc, ch, VTFT, 0xffff); emu_wrptr(sc, ch, CVCF, 0xffff); emu_wrptr(sc, ch, PTRX, 0); emu_wrptr(sc, ch, CPF, 0); emu_wrptr(sc, ch, CCR, 0); emu_wrptr(sc, ch, PSST, 0); emu_wrptr(sc, ch, DSL, 0x10); emu_wrptr(sc, ch, CCCA, 0); emu_wrptr(sc, ch, Z1, 0); emu_wrptr(sc, ch, Z2, 0); emu_wrptr(sc, ch, FXRT, 0xd01c0000); emu_wrptr(sc, ch, ATKHLDM, 0); emu_wrptr(sc, ch, DCYSUSM, 0); emu_wrptr(sc, ch, IFATN, 0xffff); emu_wrptr(sc, ch, PEFE, 0); emu_wrptr(sc, ch, FMMOD, 0); emu_wrptr(sc, ch, TREMFRQ, 24); /* 1 Hz */ emu_wrptr(sc, ch, FM2FRQ2, 24); /* 1 Hz */ emu_wrptr(sc, ch, TEMPENV, 0); /*** these are last so OFF prevents writing ***/ emu_wrptr(sc, ch, LFOVAL2, 0); emu_wrptr(sc, ch, LFOVAL1, 0); emu_wrptr(sc, ch, ATKHLDV, 0); emu_wrptr(sc, ch, ENVVOL, 0); emu_wrptr(sc, ch, ENVVAL, 0); sc->voice[ch].vnum = ch; sc->voice[ch].slave = NULL; sc->voice[ch].busy = 0; sc->voice[ch].ismaster = 0; sc->voice[ch].running = 0; sc->voice[ch].b16 = 0; sc->voice[ch].stereo = 0; sc->voice[ch].speed = 0; sc->voice[ch].start = 0; sc->voice[ch].end = 0; sc->voice[ch].channel = NULL; } sc->pnum = sc->rnum = 0; /* * Init to 0x02109204 : * Clock accuracy = 0 (1000ppm) * Sample Rate = 2 (48kHz) * Audio Channel = 1 (Left of 2) * Source Number = 0 (Unspecified) * Generation Status = 1 (Original for Cat Code 12) * Cat Code = 12 (Digital Signal Mixer) * Mode = 0 (Mode 0) * Emphasis = 0 (None) * CP = 1 (Copyright unasserted) * AN = 0 (Audio data) * P = 0 (Consumer) */ spcs = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; emu_wrptr(sc, 0, SPCS0, spcs); emu_wrptr(sc, 0, SPCS1, spcs); emu_wrptr(sc, 0, SPCS2, spcs); emu_initefx(sc); SLIST_INIT(&sc->mem.blocks); sc->mem.ptb_pages = emu_malloc(sc, MAXPAGES * sizeof(u_int32_t), &sc->mem.ptb_pages_addr); if (sc->mem.ptb_pages == NULL) return -1; sc->mem.silent_page = emu_malloc(sc, EMUPAGESIZE, &sc->mem.silent_page_addr); if (sc->mem.silent_page == NULL) { emu_free(sc, sc->mem.ptb_pages); return -1; } /* Clear page with silence & setup all pointers to this page */ bzero(sc->mem.silent_page, EMUPAGESIZE); tmp = (u_int32_t)(sc->mem.silent_page_addr) << 1; for (i = 0; i < MAXPAGES; i++) sc->mem.ptb_pages[i] = tmp | i; emu_wrptr(sc, 0, PTB, (sc->mem.ptb_pages_addr)); emu_wrptr(sc, 0, TCB, 0); /* 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); emu_wrptr(sc, ch, MAPB, tmp | MAP_PTI_MASK); } /* emu_memalloc(sc, EMUPAGESIZE); */ /* * Hokay, now enable the AUD bit * Enable Audio = 1 * Mute Disable Audio = 0 * Lock Tank Memory = 1 * Lock Sound Memory = 0 * Auto Mute = 1 */ tmp = HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE; if (sc->rev >= 6) tmp |= HCFG_JOYENABLE; emu_wr(sc, HCFG, tmp, 4); /* TOSLink detection */ sc->tos_link = 0; tmp = emu_rd(sc, HCFG, 4); if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { emu_wr(sc, HCFG, tmp | 0x800, 4); DELAY(50); if (tmp != (emu_rd(sc, HCFG, 4) & ~0x800)) { sc->tos_link = 1; emu_wr(sc, HCFG, tmp, 4); } } return 0; } static int emu_uninit(struct sc_info *sc) { u_int32_t ch; emu_wr(sc, INTE, 0, 4); for (ch = 0; ch < NUM_G; ch++) emu_wrptr(sc, ch, DCYSUSV, ENV_OFF); for (ch = 0; ch < NUM_G; ch++) { emu_wrptr(sc, ch, VTFT, 0); emu_wrptr(sc, ch, CVCF, 0); emu_wrptr(sc, ch, PTRX, 0); emu_wrptr(sc, ch, CPF, 0); } /* disable audio and lock cache */ emu_wr(sc, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, 4); emu_wrptr(sc, 0, PTB, 0); /* reset recording buffers */ emu_wrptr(sc, 0, MICBS, ADCBS_BUFSIZE_NONE); emu_wrptr(sc, 0, MICBA, 0); emu_wrptr(sc, 0, FXBS, ADCBS_BUFSIZE_NONE); emu_wrptr(sc, 0, FXBA, 0); emu_wrptr(sc, 0, FXWC, 0); emu_wrptr(sc, 0, ADCBS, ADCBS_BUFSIZE_NONE); emu_wrptr(sc, 0, ADCBA, 0); emu_wrptr(sc, 0, TCB, 0); emu_wrptr(sc, 0, TCBS, 0); /* disable channel interrupt */ emu_wrptr(sc, 0, CLIEL, 0); emu_wrptr(sc, 0, CLIEH, 0); emu_wrptr(sc, 0, SOLEL, 0); emu_wrptr(sc, 0, SOLEH, 0); /* init envelope engine */ if (!SLIST_EMPTY(&sc->mem.blocks)) device_printf(sc->dev, "warning: memblock list not empty\n"); emu_free(sc, sc->mem.ptb_pages); emu_free(sc, sc->mem.silent_page); return 0; } static int emu_pci_probe(device_t dev) { char *s = NULL; switch (pci_get_devid(dev)) { case EMU10K1_PCI_ID: s = "Creative EMU10K1"; break; /* case EMU10K2_PCI_ID: s = "Creative EMU10K2"; break; */ default: return ENXIO; } device_set_desc(dev, s); return 0; } static int emu_pci_attach(device_t dev) { struct ac97_info *codec = NULL; struct sc_info *sc; u_int32_t data; int i, gotmic; char status[SND_STATUSLEN]; if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) { device_printf(dev, "cannot allocate softc\n"); return ENXIO; } sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); sc->dev = dev; sc->type = pci_get_devid(dev); sc->rev = pci_get_revid(dev); data = pci_read_config(dev, PCIR_COMMAND, 2); data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); pci_write_config(dev, PCIR_COMMAND, data, 2); data = pci_read_config(dev, PCIR_COMMAND, 2); i = PCIR_BAR(0); sc->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &i, 0, ~0, 1, RF_ACTIVE); if (sc->reg == NULL) { device_printf(dev, "unable to map register space\n"); goto bad; } sc->st = rman_get_bustag(sc->reg); sc->sh = rman_get_bushandle(sc->reg); sc->bufsz = pcm_getbuffersize(dev, 4096, EMU_DEFAULT_BUFSZ, 65536); if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, /*lowaddr*/1 << 31, /* can only access 0-2gb */ /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, /*flags*/0, /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, &sc->parent_dmat) != 0) { device_printf(dev, "unable to create dma tag\n"); goto bad; } if (emu_init(sc) == -1) { device_printf(dev, "unable to initialize the card\n"); goto bad; } codec = AC97_CREATE(dev, sc, emu_ac97); if (codec == NULL) goto bad; gotmic = (ac97_getcaps(codec) & AC97_CAP_MICCHANNEL) ? 1 : 0; if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; i = 0; sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &i, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", rman_get_start(sc->reg), rman_get_start(sc->irq)); if (pcm_register(dev, sc, EMU_CHANS, gotmic ? 3 : 2)) goto bad; for (i = 0; i < EMU_CHANS; i++) pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc); for (i = 0; i < (gotmic ? 3 : 2); i++) pcm_addchan(dev, PCMDIR_REC, &emurchan_class, sc); pcm_setstatus(dev, status); return 0; bad: if (codec) ac97_destroy(codec); if (sc->reg) bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg); if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih); if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat); if (sc->lock) snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return ENXIO; } static int emu_pci_detach(device_t dev) { int r; struct sc_info *sc; r = pcm_unregister(dev); if (r) return r; sc = pcm_getdevinfo(dev); /* shutdown chip */ emu_uninit(sc); bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg); bus_teardown_intr(dev, sc->irq, sc->ih); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); bus_dma_tag_destroy(sc->parent_dmat); snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return 0; } /* add suspend, resume */ static device_method_t emu_methods[] = { /* Device interface */ DEVMETHOD(device_probe, emu_pci_probe), DEVMETHOD(device_attach, emu_pci_attach), DEVMETHOD(device_detach, emu_pci_detach), { 0, 0 } }; static driver_t emu_driver = { "pcm", emu_methods, PCM_SOFTC_SIZE, }; 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) { char *s = NULL; switch (pci_get_devid(dev)) { case 0x70021102: s = "Creative EMU10K1 Joystick"; device_quiet(dev); break; case 0x70031102: s = "Creative EMU10K2 Joystick"; device_quiet(dev); break; } if (s) device_set_desc(dev, s); return s ? -1000 : ENXIO; } static int emujoy_pci_attach(device_t dev) { return 0; } static int emujoy_pci_detach(device_t dev) { return 0; } static device_method_t emujoy_methods[] = { DEVMETHOD(device_probe, emujoy_pci_probe), DEVMETHOD(device_attach, emujoy_pci_attach), DEVMETHOD(device_detach, emujoy_pci_detach), { 0, 0 } }; static driver_t emujoy_driver = { "emujoy", emujoy_methods, 8, }; static devclass_t emujoy_devclass; DRIVER_MODULE(emujoy, pci, emujoy_driver, emujoy_devclass, 0, 0); Index: head/sys/gnu/dev/sound/pci/emu10k1.h =================================================================== --- head/sys/gnu/dev/sound/pci/emu10k1.h (revision 124276) +++ head/sys/gnu/dev/sound/pci/emu10k1.h (revision 124277) @@ -1,674 +1,740 @@ /* ********************************************************************** * emu10k1.h, derived from 8010.h - * Copyright 1999, 2000 Creative Labs, Inc. + * Copyright 1999-2001 Creative Labs, Inc. * ********************************************************************** * * Date Author Summary of changes * ---- ------ ------------------ * October 20, 1999 Bertrand Lee base code release * November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS * line endings * December 8, 1999 Jon Taylor Added lots of new register info + * May 16, 2001 Daniel Bertrand Added unofficial DBG register info + * Oct-Nov 2001 D.B. Added unofficial Audigy registers * ********************************************************************** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, * USA. * * ********************************************************************** * $FreeBSD$ */ -#ifndef EMU10K1_H -#define EMU10K1_H +#ifndef _8010_H +#define _8010_H -/* ------------------- DEFINES -------------------- */ + /* +#include + */ -#define EMUPAGESIZE 4096 /* don't change */ -#define MAXREQVOICES 8 -#define MAXPAGES (32768 * 64 / EMUPAGESIZE) /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */ -#define RESERVED 0 -#define NUM_MIDI 16 -#define NUM_G 64 /* use all channels */ -#define NUM_FXSENDS 4 +// Driver version: +#define MAJOR_VER 0 +#define MINOR_VER 20 +#define DRIVER_VERSION "0.20a" -#define TMEMSIZE 256*1024 -#define TMEMSIZEREG 4 +// Audigy specify registers are prefixed with 'A_' -#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL)) - /************************************************************************************************/ /* PCI function 0 registers, address = + PCIBASE0 */ /************************************************************************************************/ #define PTR 0x00 /* Indexed register set pointer register */ /* NOTE: The CHANNELNUM and ADDRESS words can */ /* be modified independently of each other. */ #define PTR_CHANNELNUM_MASK 0x0000003f /* For each per-channel register, indicates the */ /* channel number of the register to be */ /* accessed. For non per-channel registers the */ /* value should be set to zero. */ #define PTR_ADDRESS_MASK 0x07ff0000 /* Register index */ #define DATA 0x04 /* Indexed register set data register */ #define IPR 0x08 /* Global interrupt pending register */ /* Clear pending interrupts by writing a 1 to */ /* the relevant bits and zero to the other bits */ + +/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */ +#define A_IPR_MIDITRANSBUFEMPTY2 0x10000000 /* MIDI UART transmit buffer empty */ +#define A_IPR_MIDIRECVBUFEMPTY2 0x08000000 /* MIDI UART receive buffer empty */ + #define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */ #define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */ #define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */ #define IPR_PCIERROR 0x00200000 /* PCI bus error */ #define IPR_VOLINCR 0x00100000 /* Volume increment button pressed */ #define IPR_VOLDECR 0x00080000 /* Volume decrement button pressed */ #define IPR_MUTE 0x00040000 /* Mute button pressed */ #define IPR_MICBUFFULL 0x00020000 /* Microphone buffer full */ #define IPR_MICBUFHALFFULL 0x00010000 /* Microphone buffer half full */ #define IPR_ADCBUFFULL 0x00008000 /* ADC buffer full */ #define IPR_ADCBUFHALFFULL 0x00004000 /* ADC buffer half full */ #define IPR_EFXBUFFULL 0x00002000 /* Effects buffer full */ #define IPR_EFXBUFHALFFULL 0x00001000 /* Effects buffer half full */ #define IPR_GPSPDIFSTATUSCHANGE 0x00000800 /* GPSPDIF channel status change */ #define IPR_CDROMSTATUSCHANGE 0x00000400 /* CD-ROM channel status change */ #define IPR_INTERVALTIMER 0x00000200 /* Interval timer terminal count */ #define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */ #define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */ #define IPR_CHANNELLOOP 0x00000040 /* One or more channel loop interrupts pending */ #define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */ /* Highest set channel in CLIPL or CLIPH. When */ /* IP is written with CL set, the bit in CLIPL */ /* or CLIPH corresponding to the CIN value */ /* written will be cleared. */ +#define A_IPR_MIDITRANSBUFEMPTY1 IPR_MIDITRANSBUFEMPTY /* MIDI UART transmit buffer empty */ +#define A_IPR_MIDIRECVBUFEMPTY1 IPR_MIDIRECVBUFEMPTY /* MIDI UART receive buffer empty */ + + #define INTE 0x0c /* Interrupt enable register */ #define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */ #define INTE_VIRTUALSB_220 0x00000000 /* Capture at I/O base address 0x220-0x22f */ #define INTE_VIRTUALSB_240 0x40000000 /* Capture at I/O base address 0x240 */ #define INTE_VIRTUALSB_260 0x80000000 /* Capture at I/O base address 0x260 */ #define INTE_VIRTUALSB_280 0xc0000000 /* Capture at I/O base address 0x280 */ #define INTE_VIRTUALMPU_MASK 0x30000000 /* Virtual MPU I/O port capture */ #define INTE_VIRTUALMPU_300 0x00000000 /* Capture at I/O base address 0x300-0x301 */ #define INTE_VIRTUALMPU_310 0x10000000 /* Capture at I/O base address 0x310 */ #define INTE_VIRTUALMPU_320 0x20000000 /* Capture at I/O base address 0x320 */ #define INTE_VIRTUALMPU_330 0x30000000 /* Capture at I/O base address 0x330 */ #define INTE_MASTERDMAENABLE 0x08000000 /* Master DMA emulation at 0x000-0x00f */ #define INTE_SLAVEDMAENABLE 0x04000000 /* Slave DMA emulation at 0x0c0-0x0df */ #define INTE_MASTERPICENABLE 0x02000000 /* Master PIC emulation at 0x020-0x021 */ #define INTE_SLAVEPICENABLE 0x01000000 /* Slave PIC emulation at 0x0a0-0x0a1 */ #define INTE_VSBENABLE 0x00800000 /* Enable virtual Soundblaster */ #define INTE_ADLIBENABLE 0x00400000 /* Enable AdLib emulation at 0x388-0x38b */ #define INTE_MPUENABLE 0x00200000 /* Enable virtual MPU */ #define INTE_FORCEINT 0x00100000 /* Continuously assert INTAN */ #define INTE_MRHANDENABLE 0x00080000 /* Enable the "Mr. Hand" logic */ /* NOTE: There is no reason to use this under */ /* Linux, and it will cause odd hardware */ /* behavior and possibly random segfaults and */ /* lockups if enabled. */ +/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */ +#define A_INTE_MIDITXENABLE2 0x00020000 /* Enable MIDI transmit-buffer-empty interrupts */ +#define A_INTE_MIDIRXENABLE2 0x00010000 /* Enable MIDI receive-buffer-empty interrupts */ + + #define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */ /* NOTE: This bit must always be enabled */ #define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */ #define INTE_PCIERRORENABLE 0x00000800 /* Enable PCI bus error interrupts */ #define INTE_VOLINCRENABLE 0x00000400 /* Enable volume increment button interrupts */ #define INTE_VOLDECRENABLE 0x00000200 /* Enable volume decrement button interrupts */ #define INTE_MUTEENABLE 0x00000100 /* Enable mute button interrupts */ #define INTE_MICBUFENABLE 0x00000080 /* Enable microphone buffer interrupts */ #define INTE_ADCBUFENABLE 0x00000040 /* Enable ADC buffer interrupts */ #define INTE_EFXBUFENABLE 0x00000020 /* Enable Effects buffer interrupts */ #define INTE_GPSPDIFENABLE 0x00000010 /* Enable GPSPDIF status interrupts */ #define INTE_CDSPDIFENABLE 0x00000008 /* Enable CDSPDIF status interrupts */ #define INTE_INTERVALTIMERENB 0x00000004 /* Enable interval timer interrupts */ #define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */ #define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */ +/* The next two interrupts are for the midi port on the Audigy (A_MPU2) */ +#define A_INTE_MIDITXENABLE1 INTE_MIDITXENABLE +#define A_INTE_MIDIRXENABLE1 INTE_MIDIRXENABLE + #define WC 0x10 /* Wall Clock register */ #define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */ #define WC_SAMPLECOUNTER 0x14060010 #define WC_CURRENTCHANNEL 0x0000003F /* Channel [0..63] currently being serviced */ /* NOTE: Each channel takes 1/64th of a sample */ /* period to be serviced. */ #define HCFG 0x14 /* Hardware config register */ /* NOTE: There is no reason to use the legacy */ /* SoundBlaster emulation stuff described below */ /* under Linux, and all kinds of weird hardware */ /* behavior can result if you try. Don't. */ #define HCFG_LEGACYFUNC_MASK 0xe0000000 /* Legacy function number */ #define HCFG_LEGACYFUNC_MPU 0x00000000 /* Legacy MPU */ #define HCFG_LEGACYFUNC_SB 0x40000000 /* Legacy SB */ #define HCFG_LEGACYFUNC_AD 0x60000000 /* Legacy AD */ #define HCFG_LEGACYFUNC_MPIC 0x80000000 /* Legacy MPIC */ #define HCFG_LEGACYFUNC_MDMA 0xa0000000 /* Legacy MDMA */ #define HCFG_LEGACYFUNC_SPCI 0xc0000000 /* Legacy SPCI */ #define HCFG_LEGACYFUNC_SDMA 0xe0000000 /* Legacy SDMA */ #define HCFG_IOCAPTUREADDR 0x1f000000 /* The 4 LSBs of the captured I/O address. */ #define HCFG_LEGACYWRITE 0x00800000 /* 1 = write, 0 = read */ #define HCFG_LEGACYWORD 0x00400000 /* 1 = word, 0 = byte */ #define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */ /* NOTE: The rest of the bits in this register */ /* _are_ relevant under Linux. */ #define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */ #define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */ #define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */ #define HCFG_GPINPUT0 0x00004000 /* External pin112 */ #define HCFG_GPINPUT1 0x00002000 /* External pin110 */ + #define HCFG_GPOUTPUT_MASK 0x00001c00 /* External pins which may be controlled */ +#define HCFG_GPOUT0 0x00001000 /* set to enable digital out on 5.1 cards */ + #define HCFG_JOYENABLE 0x00000200 /* Internal joystick enable */ #define HCFG_PHASETRACKENABLE 0x00000100 /* Phase tracking enable */ /* 1 = Force all 3 async digital inputs to use */ /* the same async sample rate tracker (ZVIDEO) */ #define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */ #define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */ #define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */ +#define HCFG_AC3ENABLE_GPSPDIF 0x00000020 /* Channels 0 and 1 replace GPSPDIF */ #define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */ /* will automatically mute their output when */ /* they are not rate-locked to the external */ /* async audio source */ #define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */ /* NOTE: This should generally never be used. */ #define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ /* NOTE: This should generally never be used. */ +#define HCFG_LOCKTANKCACHE 0x01020014 #define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */ /* NOTE: This is a 'cheap' way to implement a */ /* master mute function on the mute button, and */ /* in general should not be used unless a more */ /* sophisticated master mute function has not */ /* been written. */ #define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */ /* Should be set to 1 when the EMU10K1 is */ /* completely initialized. */ +//For Audigy, MPU port move to 0x70-0x74 ptr register + #define MUDATA 0x18 /* MPU401 data register (8 bits) */ #define MUCMD 0x19 /* MPU401 command register (8 bits) */ #define MUCMD_RESET 0xff /* RESET command */ #define MUCMD_ENTERUARTMODE 0x3f /* Enter_UART_mode command */ /* NOTE: All other commands are ignored */ #define MUSTAT MUCMD /* MPU401 status register (8 bits) */ #define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */ #define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */ -#define TIMER 0x1a /* Timer terminal count register */ +#define A_IOCFG 0x18 /* GPIO on Audigy card (16bits) */ +#define A_GPINPUT_MASK 0xff00 +#define A_GPOUTPUT_MASK 0x00ff + +#define TIMER 0x1a /* Timer terminal count register (16-bit) */ /* NOTE: After the rate is changed, a maximum */ /* of 1024 sample periods should be allowed */ /* before the new rate is guaranteed accurate. */ -#define TIMER_RATE_MASK 0x000003ff /* Timer interrupt rate in sample periods */ +#define TIMER_RATE_MASK 0x03ff /* Timer interrupt rate in sample periods */ /* 0 == 1024 periods, [1..4] are not useful */ -#define TIMER_RATE 0x0a00001a #define AC97DATA 0x1c /* AC97 register set data register (16 bit) */ #define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */ #define AC97ADDRESS_READY 0x80 /* Read-only bit, reflects CODEC READY signal */ #define AC97ADDRESS_ADDRESS 0x7f /* Address of indexed AC97 register */ -/************************************************************************************************/ -/* PCI function 1 registers, address = + PCIBASE1 */ -/************************************************************************************************/ - -#define JOYSTICK1 0x00 /* Analog joystick port register */ -#define JOYSTICK2 0x01 /* Analog joystick port register */ -#define JOYSTICK3 0x02 /* Analog joystick port register */ -#define JOYSTICK4 0x03 /* Analog joystick port register */ -#define JOYSTICK5 0x04 /* Analog joystick port register */ -#define JOYSTICK6 0x05 /* Analog joystick port register */ -#define JOYSTICK7 0x06 /* Analog joystick port register */ -#define JOYSTICK8 0x07 /* Analog joystick port register */ - -/* When writing, any write causes JOYSTICK_COMPARATOR output enable to be pulsed on write. */ -/* When reading, use these bitfields: */ -#define JOYSTICK_BUTTONS 0x0f /* Joystick button data */ -#define JOYSTICK_COMPARATOR 0xf0 /* Joystick comparator data */ - - /********************************************************************************************************/ -/* AC97 pointer-offset register set, accessed through the AC97ADDRESS and AC97DATA registers */ -/********************************************************************************************************/ - -#define AC97_RESET 0x00 -#define AC97_MASTERVOLUME 0x02 /* Master volume */ -#define AC97_HEADPHONEVOLUME 0x04 /* Headphone volume */ -#define AC97_MASTERVOLUMEMONO 0x06 /* Mast volume mono */ -#define AC97_MASTERTONE 0x08 -#define AC97_PCBEEPVOLUME 0x0a /* PC speaker system beep volume */ -#define AC97_PHONEVOLUME 0x0c -#define AC97_MICVOLUME 0x0e -#define AC97_LINEINVOLUME 0x10 -#define AC97_CDVOLUME 0x12 -#define AC97_VIDEOVOLUME 0x14 -#define AC97_AUXVOLUME 0x16 -#define AC97_PCMOUTVOLUME 0x18 -#define AC97_RECORDSELECT 0x1a -#define AC97_RECORDGAIN 0x1c -#define AC97_RECORDGAINMIC 0x1e -#define AC97_GENERALPURPOSE 0x20 -#define AC97_3DCONTROL 0x22 -#define AC97_MODEMRATE 0x24 -#define AC97_POWERDOWN 0x26 -#define AC97_VENDORID1 0x7c -#define AC97_VENDORID2 0x7e -#define AC97_ZVIDEOVOLUME 0xec -#define AC97_AC3VOLUME 0xed - -/********************************************************************************************************/ /* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers */ /********************************************************************************************************/ #define CPF 0x00 /* Current pitch and fraction register */ #define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */ #define CPF_CURRENTPITCH 0x10100000 #define CPF_STEREO_MASK 0x00008000 /* 1 = Even channel interleave, odd channel locked */ #define CPF_STOP_MASK 0x00004000 /* 1 = Current pitch forced to 0 */ #define CPF_FRACADDRESS_MASK 0x00003fff /* Linear fractional address of the current channel */ #define PTRX 0x01 /* Pitch target and send A/B amounts register */ #define PTRX_PITCHTARGET_MASK 0xffff0000 /* Pitch target of specified channel */ #define PTRX_PITCHTARGET 0x10100001 #define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00 /* Linear level of channel output sent to FX send bus A */ #define PTRX_FXSENDAMOUNT_A 0x08080001 #define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff /* Linear level of channel output sent to FX send bus B */ #define PTRX_FXSENDAMOUNT_B 0x08000001 #define CVCF 0x02 /* Current volume and filter cutoff register */ #define CVCF_CURRENTVOL_MASK 0xffff0000 /* Current linear volume of specified channel */ #define CVCF_CURRENTVOL 0x10100002 #define CVCF_CURRENTFILTER_MASK 0x0000ffff /* Current filter cutoff frequency of specified channel */ #define CVCF_CURRENTFILTER 0x10000002 #define VTFT 0x03 /* Volume target and filter cutoff target register */ #define VTFT_VOLUMETARGET_MASK 0xffff0000 /* Volume target of specified channel */ #define VTFT_FILTERTARGET_MASK 0x0000ffff /* Filter cutoff target of specified channel */ #define Z1 0x05 /* Filter delay memory 1 register */ #define Z2 0x04 /* Filter delay memory 2 register */ #define PSST 0x06 /* Send C amount and loop start address register */ #define PSST_FXSENDAMOUNT_C_MASK 0xff000000 /* Linear level of channel output sent to FX send bus C */ #define PSST_FXSENDAMOUNT_C 0x08180006 #define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */ #define PSST_LOOPSTARTADDR 0x18000006 #define DSL 0x07 /* Send D amount and loop start address register */ #define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */ #define DSL_FXSENDAMOUNT_D 0x08180007 #define DSL_LOOPENDADDR_MASK 0x00ffffff /* Loop end address of the specified channel */ #define DSL_LOOPENDADDR 0x18000007 #define CCCA 0x08 /* Filter Q, interp. ROM, byte size, cur. addr register */ #define CCCA_RESONANCE 0xf0000000 /* Lowpass filter resonance (Q) height */ #define CCCA_INTERPROMMASK 0x0e000000 /* Selects passband of interpolation ROM */ /* 1 == full band, 7 == lowpass */ /* ROM 0 is used when pitch shifting downward or less */ /* then 3 semitones upward. Increasingly higher ROM */ /* numbers are used, typically in steps of 3 semitones, */ /* as upward pitch shifting is performed. */ #define CCCA_INTERPROM_0 0x00000000 /* Select interpolation ROM 0 */ #define CCCA_INTERPROM_1 0x02000000 /* Select interpolation ROM 1 */ #define CCCA_INTERPROM_2 0x04000000 /* Select interpolation ROM 2 */ #define CCCA_INTERPROM_3 0x06000000 /* Select interpolation ROM 3 */ #define CCCA_INTERPROM_4 0x08000000 /* Select interpolation ROM 4 */ #define CCCA_INTERPROM_5 0x0a000000 /* Select interpolation ROM 5 */ #define CCCA_INTERPROM_6 0x0c000000 /* Select interpolation ROM 6 */ #define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */ #define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */ #define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ #define CCCA_CURRADDR 0x18000008 #define CCR 0x09 /* Cache control register */ #define CCR_CACHEINVALIDSIZE 0x07190009 #define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */ #define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */ #define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */ #define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */ #define CCR_READADDRESS 0x06100009 #define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */ #define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */ /* NOTE: This is valid only if CACHELOOPFLAG is set */ #define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */ #define CCR_CACHELOOPADDRHI 0x000000ff /* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */ #define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */ /* NOTE: This register is normally not used */ #define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address (DSL_LOOPSTARTADDR [0..15]) */ #define FXRT 0x0b /* Effects send routing register */ /* NOTE: It is illegal to assign the same routing to */ /* two effects sends. */ #define FXRT_CHANNELA 0x000f0000 /* Effects send bus number for channel's effects send A */ #define FXRT_CHANNELB 0x00f00000 /* Effects send bus number for channel's effects send B */ #define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */ #define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */ #define MAPA 0x0c /* Cache map A */ #define MAPB 0x0d /* Cache map B */ #define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ #define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ #define ENVVOL 0x10 /* Volume envelope register */ #define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */ /* 0x8000-n == 666*n usec delay */ #define ATKHLDV 0x11 /* Volume envelope hold and attack register */ #define ATKHLDV_PHASE0 0x00008000 /* 0 = Begin attack phase */ #define ATKHLDV_HOLDTIME_MASK 0x00007f00 /* Envelope hold time (127-n == n*88.2msec) */ #define ATKHLDV_ATTACKTIME_MASK 0x0000007f /* Envelope attack time, log encoded */ /* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec */ #define DCYSUSV 0x12 /* Volume envelope sustain and decay register */ #define DCYSUSV_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ #define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ #define DCYSUSV_CHANNELENABLE_MASK 0x00000080 /* 1 = Inhibit envelope engine from writing values in */ /* this channel and from writing to pitch, filter and */ /* volume targets. */ #define DCYSUSV_DECAYTIME_MASK 0x0000007f /* Volume envelope decay time, log encoded */ /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */ #define LFOVAL1 0x13 /* Modulation LFO value */ #define LFOVAL_MASK 0x0000ffff /* Current value of modulation LFO state variable */ /* 0x8000-n == 666*n usec delay */ #define ENVVAL 0x14 /* Modulation envelope register */ #define ENVVAL_MASK 0x0000ffff /* Current value of modulation envelope state variable */ /* 0x8000-n == 666*n usec delay */ #define ATKHLDM 0x15 /* Modulation envelope hold and attack register */ #define ATKHLDM_PHASE0 0x00008000 /* 0 = Begin attack phase */ #define ATKHLDM_HOLDTIME 0x00007f00 /* Envelope hold time (127-n == n*42msec) */ #define ATKHLDM_ATTACKTIME 0x0000007f /* Envelope attack time, log encoded */ /* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec */ #define DCYSUSM 0x16 /* Modulation envelope decay and sustain register */ #define DCYSUSM_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ #define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ #define DCYSUSM_DECAYTIME_MASK 0x0000007f /* Envelope decay time, log encoded */ /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */ #define LFOVAL2 0x17 /* Vibrato LFO register */ #define LFOVAL2_MASK 0x0000ffff /* Current value of vibrato LFO state variable */ /* 0x8000-n == 666*n usec delay */ #define IP 0x18 /* Initial pitch register */ #define IP_MASK 0x0000ffff /* Exponential initial pitch shift */ /* 4 bits of octave, 12 bits of fractional octave */ #define IP_UNITY 0x0000e000 /* Unity pitch shift */ #define IFATN 0x19 /* Initial filter cutoff and attenuation register */ #define IFATN_FILTERCUTOFF_MASK 0x0000ff00 /* Initial filter cutoff frequency in exponential units */ /* 6 most significant bits are semitones */ /* 2 least significant bits are fractions */ #define IFATN_FILTERCUTOFF 0x08080019 #define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */ #define IFATN_ATTENUATION 0x08000019 #define PEFE 0x1a /* Pitch envelope and filter envelope amount register */ #define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */ /* Signed 2's complement, +/- one octave peak extremes */ #define PEFE_PITCHAMOUNT 0x0808001a #define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */ /* Signed 2's complement, +/- six octaves peak extremes */ #define PEFE_FILTERAMOUNT 0x0800001a #define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */ #define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */ /* Signed 2's complement, +/- one octave extremes */ #define FMMOD_MOFILTER 0x000000ff /* Filter LFO modulation depth */ /* Signed 2's complement, +/- three octave extremes */ #define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */ #define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */ /* Signed 2's complement, with +/- 12dB extremes */ +#define TREMFRQ_FREQUENCY 0x000000ff /* Tremolo LFO frequency */ + /* ??Hz steps, maximum of ?? Hz. */ #define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */ #define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */ /* Signed 2's complement, +/- one octave extremes */ #define FM2FRQ2_FREQUENCY 0x000000ff /* Vibrato LFO frequency */ /* 0.039Hz steps, maximum of 9.85 Hz. */ #define TEMPENV 0x1e /* Tempory envelope register */ #define TEMPENV_MASK 0x0000ffff /* 16-bit value */ /* NOTE: All channels contain internal variables; do */ /* not write to these locations. */ #define CD0 0x20 /* Cache data 0 register */ #define CD1 0x21 /* Cache data 1 register */ #define CD2 0x22 /* Cache data 2 register */ #define CD3 0x23 /* Cache data 3 register */ #define CD4 0x24 /* Cache data 4 register */ #define CD5 0x25 /* Cache data 5 register */ #define CD6 0x26 /* Cache data 6 register */ #define CD7 0x27 /* Cache data 7 register */ #define CD8 0x28 /* Cache data 8 register */ #define CD9 0x29 /* Cache data 9 register */ #define CDA 0x2a /* Cache data A register */ #define CDB 0x2b /* Cache data B register */ #define CDC 0x2c /* Cache data C register */ #define CDD 0x2d /* Cache data D register */ #define CDE 0x2e /* Cache data E register */ #define CDF 0x2f /* Cache data F register */ #define PTB 0x40 /* Page table base register */ #define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */ #define TCB 0x41 /* Tank cache base register */ #define TCB_MASK 0xfffff000 /* Physical address of the bottom of host based TRAM */ #define ADCCR 0x42 /* ADC sample rate/stereo control register */ #define ADCCR_RCHANENABLE 0x00000010 /* Enables right channel for writing to the host */ #define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */ /* NOTE: To guarantee phase coherency, both channels */ /* must be disabled prior to enabling both channels. */ +#define A_ADCCR_RCHANENABLE 0x00000020 +#define A_ADCCR_LCHANENABLE 0x00000010 + +#define A_ADCCR_SAMPLERATE_MASK 0x0000000F /* Audigy sample rate convertor output rate */ #define ADCCR_SAMPLERATE_MASK 0x00000007 /* Sample rate convertor output rate */ + #define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */ #define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */ #define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */ #define ADCCR_SAMPLERATE_24 0x00000003 /* 24kHz sample rate */ #define ADCCR_SAMPLERATE_22 0x00000004 /* 22.05kHz sample rate */ #define ADCCR_SAMPLERATE_16 0x00000005 /* 16kHz sample rate */ #define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */ #define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz sample rate */ +#define A_ADCCR_SAMPLERATE_12 0x00000006 /* 12kHz sample rate */ +#define A_ADCCR_SAMPLERATE_11 0x00000007 /* 11.025kHz sample rate */ +#define A_ADCCR_SAMPLERATE_8 0x00000008 /* 8kHz sample rate */ + #define FXWC 0x43 /* FX output write channels register */ /* When set, each bit enables the writing of the */ - /* corresponding FX output channel into host memory */ - + /* corresponding FX output channel (internal registers */ + /* 0x20-0x3f) into host memory. This mode of recording */ + /* is 16bit, 48KHz only. All 32 channels can be enabled */ + /* simultaneously. */ #define TCBS 0x44 /* Tank cache buffer size register */ #define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ #define TCBS_BUFFSIZE_16K 0x00000000 #define TCBS_BUFFSIZE_32K 0x00000001 #define TCBS_BUFFSIZE_64K 0x00000002 #define TCBS_BUFFSIZE_128K 0x00000003 #define TCBS_BUFFSIZE_256K 0x00000004 #define TCBS_BUFFSIZE_512K 0x00000005 #define TCBS_BUFFSIZE_1024K 0x00000006 #define TCBS_BUFFSIZE_2048K 0x00000007 #define MICBA 0x45 /* AC97 microphone buffer address register */ #define MICBA_MASK 0xfffff000 /* 20 bit base address */ #define ADCBA 0x46 /* ADC buffer address register */ #define ADCBA_MASK 0xfffff000 /* 20 bit base address */ #define FXBA 0x47 /* FX Buffer Address */ #define FXBA_MASK 0xfffff000 /* 20 bit base address */ #define MICBS 0x49 /* Microphone buffer size register */ #define ADCBS 0x4a /* ADC buffer size register */ #define FXBS 0x4b /* FX buffer size register */ /* The following mask values define the size of the ADC, MIX and FX buffers in bytes */ #define ADCBS_BUFSIZE_NONE 0x00000000 #define ADCBS_BUFSIZE_384 0x00000001 #define ADCBS_BUFSIZE_448 0x00000002 #define ADCBS_BUFSIZE_512 0x00000003 #define ADCBS_BUFSIZE_640 0x00000004 #define ADCBS_BUFSIZE_768 0x00000005 #define ADCBS_BUFSIZE_896 0x00000006 #define ADCBS_BUFSIZE_1024 0x00000007 #define ADCBS_BUFSIZE_1280 0x00000008 #define ADCBS_BUFSIZE_1536 0x00000009 #define ADCBS_BUFSIZE_1792 0x0000000a #define ADCBS_BUFSIZE_2048 0x0000000b #define ADCBS_BUFSIZE_2560 0x0000000c #define ADCBS_BUFSIZE_3072 0x0000000d #define ADCBS_BUFSIZE_3584 0x0000000e #define ADCBS_BUFSIZE_4096 0x0000000f #define ADCBS_BUFSIZE_5120 0x00000010 #define ADCBS_BUFSIZE_6144 0x00000011 #define ADCBS_BUFSIZE_7168 0x00000012 #define ADCBS_BUFSIZE_8192 0x00000013 #define ADCBS_BUFSIZE_10240 0x00000014 #define ADCBS_BUFSIZE_12288 0x00000015 #define ADCBS_BUFSIZE_14366 0x00000016 #define ADCBS_BUFSIZE_16384 0x00000017 #define ADCBS_BUFSIZE_20480 0x00000018 #define ADCBS_BUFSIZE_24576 0x00000019 #define ADCBS_BUFSIZE_28672 0x0000001a #define ADCBS_BUFSIZE_32768 0x0000001b #define ADCBS_BUFSIZE_40960 0x0000001c #define ADCBS_BUFSIZE_49152 0x0000001d #define ADCBS_BUFSIZE_57344 0x0000001e #define ADCBS_BUFSIZE_65536 0x0000001f #define CDCS 0x50 /* CD-ROM digital channel status register */ #define GPSCS 0x51 /* General Purpose SPDIF channel status register*/ #define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ +/* definitions for debug register - taken from the alsa drivers */ +#define DBG_ZC 0x80000000 /* zero tram counter */ +#define DBG_SATURATION_OCCURED 0x02000000 /* saturation control */ +#define DBG_SATURATION_ADDR 0x01ff0000 /* saturation address */ +#define DBG_SINGLE_STEP 0x00008000 /* single step mode */ +#define DBG_STEP 0x00004000 /* start single step */ +#define DBG_CONDITION_CODE 0x00003e00 /* condition code */ +#define DBG_SINGLE_STEP_ADDR 0x000001ff /* single step address */ + + #define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ +#define A_DBG 0x53 +#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */ +#define A_DBG_ZC 0x40000000 /* zero tram counter */ +#define A_DBG_STEP_ADDR 0x000003ff +#define A_DBG_SATURATION_OCCURED 0x20000000 +#define A_DBG_SATURATION_ADDR 0x0ffc0000 + #define SPCS0 0x54 /* SPDIF output Channel Status 0 register */ #define SPCS1 0x55 /* SPDIF output Channel Status 1 register */ #define SPCS2 0x56 /* SPDIF output Channel Status 2 register */ #define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */ #define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */ #define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */ #define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */ #define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */ #define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */ #define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */ #define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */ #define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */ #define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */ #define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */ #define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */ #define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */ #define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */ #define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */ #define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */ #define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */ #define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */ #define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */ #define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */ #define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */ #define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */ #define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */ /* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */ #define CLIEL 0x58 /* Channel loop interrupt enable low register */ #define CLIEH 0x59 /* Channel loop interrupt enable high register */ #define CLIPL 0x5a /* Channel loop interrupt pending low register */ #define CLIPH 0x5b /* Channel loop interrupt pending high register */ #define SOLEL 0x5c /* Stop on loop enable low register */ #define SOLEH 0x5d /* Stop on loop enable high register */ #define SPBYPASS 0x5e /* SPDIF BYPASS mode register */ #define SPBYPASS_ENABLE 0x00000001 /* Enable SPDIF bypass mode */ +#define AC97SLOT 0x5f /* additional AC97 slots enable bits */ +#define AC97SLOT_CNTR 0x10 /* Center enable */ +#define AC97SLOT_LFE 0x20 /* LFE enable */ + #define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ #define GPSRCS 0x61 /* General Purpose SPDIF sample rate cvt status */ #define ZVSRCS 0x62 /* ZVideo sample rate converter status */ /* NOTE: This one has no SPDIFLOCKED field */ /* Assumes sample lock */ /* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */ #define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */ #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ #define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ + +/* Note that these values can vary +/- by a small amount */ +#define SRCS_SPDIFRATE_44 0x0003acd9 +#define SRCS_SPDIFRATE_48 0x00040000 +#define SRCS_SPDIFRATE_96 0x00080000 + #define MICIDX 0x63 /* Microphone recording buffer index register */ #define MICIDX_MASK 0x0000ffff /* 16-bit value */ #define MICIDX_IDX 0x10000063 +#define A_ADCIDX 0x63 +#define A_ADCIDX_IDX 0x10000063 + #define ADCIDX 0x64 /* ADC recording buffer index register */ #define ADCIDX_MASK 0x0000ffff /* 16 bit index field */ #define ADCIDX_IDX 0x10000064 #define FXIDX 0x65 /* FX recording buffer index register */ #define FXIDX_MASK 0x0000ffff /* 16-bit value */ #define FXIDX_IDX 0x10000065 +/* This is the MPU port on the card (via the game port) */ +#define A_MUDATA1 0x70 +#define A_MUCMD1 0x71 +#define A_MUSTAT1 A_MUCMD1 + +/* This is the MPU port on the Audigy Drive */ +#define A_MUDATA2 0x72 +#define A_MUCMD2 0x73 +#define A_MUSTAT2 A_MUCMD2 + +/* The next two are the Audigy equivalent of FXWC */ +/* the Audigy can record any output (16bit, 48kHz, up to 64 channel simultaneously) */ +/* Each bit selects a channel for recording */ +#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */ +#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ + +#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ +#define A_SPDIF_48000 0x00000080 +#define A_SPDIF_44100 0x00000000 +#define A_SPDIF_96000 0x00000040 + +#define A_FXRT2 0x7c +#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ +#define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */ +#define A_FXRT_CHANNELG 0x003f0000 /* Effects send bus number for channel's effects send G */ +#define A_FXRT_CHANNELH 0x3f000000 /* Effects send bus number for channel's effects send H */ + +#define A_SENDAMOUNTS 0x7d +#define A_FXSENDAMOUNT_E_MASK 0xff000000 +#define A_FXSENDAMOUNT_F_MASK 0x00ff0000 +#define A_FXSENDAMOUNT_G_MASK 0x0000ff00 +#define A_FXSENDAMOUNT_H_MASK 0x000000ff + +/* The send amounts for this one are the same as used with the emu10k1 */ +#define A_FXRT1 0x7e +#define A_FXRT_CHANNELA 0x0000003f +#define A_FXRT_CHANNELB 0x00003f00 +#define A_FXRT_CHANNELC 0x003f0000 +#define A_FXRT_CHANNELD 0x3f000000 + + /* Each FX general purpose register is 32 bits in length, all bits are used */ #define FXGPREGBASE 0x100 /* FX general purpose registers base */ - +#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */ /* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */ /* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */ /* locations are for external TRAM. */ #define TANKMEMDATAREGBASE 0x200 /* Tank memory data registers base */ #define TANKMEMDATAREG_MASK 0x000fffff /* 20 bit tank audio data field */ /* Combined address field and memory opcode or flag field. 160 locations, last 32 are external */ #define TANKMEMADDRREGBASE 0x300 /* Tank memory address registers base */ #define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ #define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ #define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ #define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ #define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ #define MICROCODEBASE 0x400 /* Microcode data base address */ /* Each DSP microcode instruction is mapped into 2 doublewords */ /* NOTE: When writing, always write the LO doubleword first. Reads can be in either order. */ #define LOWORD_OPX_MASK 0x000ffc00 /* Instruction operand X */ #define LOWORD_OPY_MASK 0x000003ff /* Instruction operand Y */ #define HIWORD_OPCODE_MASK 0x00f00000 /* Instruction opcode */ #define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */ #define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */ -#define ENABLE 0xffffffff -#define DISABLE 0x00000000 -#define ENV_ON 0x80 -#define ENV_OFF 0x00 +/* Audigy Soundcard have a different instruction format */ +#define AUDIGY_CODEBASE 0x600 +#define A_LOWORD_OPY_MASK 0x000007ff +#define A_LOWORD_OPX_MASK 0x007ff000 +#define A_HIWORD_OPCODE_MASK 0x0f000000 +#define A_HIWORD_RESULT_MASK 0x007ff000 +#define A_HIWORD_OPA_MASK 0x000007ff -#endif /* EMU10K1_H */ + +#endif /* _8010_H */